//1.0.0 版陪玩机器人
let logic = module.exports;
const gameProto = require('./gameProto');
const GameLogic = require('./gameLogic');
const utils = require('../../util/utils');
let MAX_COUNT = 16;
let GAME_PLAYER = 3;
class AiLogic {

    constructor(gameRule) {
        this.gameRule = gameRule;
        this.cards = null;
        this.gameLogic = new GameLogic(gameRule);
        this.curOperateUid = null; //当前操作玩家
        this.lastOperateUid = null; //最后一个出牌的玩家
        this.baoDanUser = []; //报单玩家
        this.userList = {}; //玩家位置
        this.maxList = {};
    }
    userReSortCard(handCardDataArr, isRobot) {
        // --作弊方先出（ 出牌方必须要黑桃三）
        let handCardDat = {};
        handCardDat.DanPai = 0;
        handCardDat.DuiZi = 0;
        handCardDat.SanZhang = 0;
        handCardDat.SanDaiEr = 0;
        handCardDat.ShunZi = 0;
        handCardDat.ZhaDan = 0;
        let isHaoHuai = false;
        // --好牌烂牌， 只发给一个人 / 或者一个机器人
        if (isRobot) {
            let Haohandutils = utils.getRandomNum(0, 31);
            isHaoHuai = true;
            //1 % 1 副炸弹， 4个对子， 4 个单牌
            if (Haohandutils == 0) {
                handCardDat.DanPai = parseInt(this.gameRule.cardCount) == 16 ? 4 : 3;
                handCardDat.DuiZi = 4;
                handCardDat.ZhaDan = 1;
            } else if (Haohandutils >= 1 || Haohandutils <= 5) { //5 % 1 个炸弹， 两个三带二， 2 个单牌
                handCardDat.DanPai = parseInt(this.gameRule.cardCount) == 16 ? 2 : 1;
                handCardDat.DuiZi = 1;
                handCardDat.SanZhang = 2;
                handCardDat.ZhaDan = 1;
            } else if (Haohandutils >= 6 || Haohandutils <= 10) { //5 %  一个顺子， 三带二， 4个对子
                if (parseInt(this.gameRule.cardCount) == 16) {
                    handCardDat.DuiZi = 4;
                } else {
                    handCardDat.DuiZi = 3;
                    handCardDat.DanPai = 1;
                }
                handCardDat.SanZhang = 1;
                handCardDat.ShunZi = 1;
                // handCardDat.ZhaDan = 1;
            } else if (Haohandutils >= 11 || Haohandutils <= 31) { //20 % 一个顺子， 1 个三带二， 三个对子
                if (parseInt(this.gameRule.cardCount) == 16) {
                    handCardDat.DuiZi = 4;
                } else {
                    handCardDat.DuiZi = 3;
                    handCardDat.DanPai = 1;
                }
                handCardDat.SanZhang = 1;
                handCardDat.ShunZi = 1;
            }

        } else {
            let Huaihandutils = utils.getRandomNum(0, 85);
            isHaoHuai = false;
            //烂牌
            //单牌K以下的， 不连续的
            //对子， 顺子J以下的， 三张9, 以下的
            //20 % 1 个三张， 3 个对子， 7 张单牌
            if (Huaihandutils >= 0 || Huaihandutils <= 20) {
                handCardDat.DanPai = parseInt(this.gameRule.cardCount) == 16 ? 7 : 6;
                handCardDat.DuiZi = 3;
                handCardDat.SanZhang = 1;
            } else if (Huaihandutils >= 21 || Huaihandutils <= 35) { //15 % 5 个对子， 6 张单牌
                handCardDat.DanPai = parseInt(this.gameRule.cardCount) == 16 ? 6 : 5;
                handCardDat.DuiZi = 5;
            } else if (Huaihandutils >= 36 || Huaihandutils <= 50) { //15 % 1 个顺子， 一个三张， 一个对子， 6 张单牌
                handCardDat.DanPai = parseInt(this.gameRule.cardCount) == 16 ? 6 : 5;
                handCardDat.DuiZi = 1;
                handCardDat.SanZhang = 1;
                handCardDat.ShunZi = 1;
            } else if (Huaihandutils >= 51 || Huaihandutils <= 65) { //15 % 2 个三张, 一个对子, 8 张单牌
                handCardDat.DanPai = parseInt(this.gameRule.cardCount) == 16 ? 8 : 7;
                handCardDat.DuiZi = 1;
                handCardDat.SanZhang = 2;
            } else if (Huaihandutils >= 66 || Huaihandutils <= 85) { //20 % 4 个对子， 一个三张， 5 张单牌
                handCardDat.DanPai = parseInt(this.gameRule.cardCount) == 16 ? 5 : 4;
                handCardDat.DuiZi = 4;
                handCardDat.SanZhang = 1;
            }
        }

        let allCardData = this.gameLogic.getWashedCards(handCardDataArr);
        if (allCardData.length < 20) {
            return null;
        }
        return this.siftHandCardList(handCardDat, allCardData, isHaoHuai);
    }
    siftHandCardList(handCardDat, CardData, isHaoHuai = false) {

        let handCardDataArr = [];
        // 0x01, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,	//方块 A - K
        // 0x11, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D,	//梅花 A - K
        // 0x21, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D,	//红桃 A - K
        // 0x02, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D,	//黑桃 A - K
        let warningSum = 0;
        //获取规则 牌张数
        let cardCount = parseInt(this.gameRule.cardCount);
        let allCardData = CardData.slice();
        //记录已经校验好的数据 
        let linwarningSum = false;
        let handCardlist = {
            DanPai: [],
            DuiZi: [],
            SanZhang: [],
            SanDaiEr: [],
            ShunZi: [],
            ZhaDan: [],
        };
        //获取新牌库
        do {
            warningSum++;
            for (let k = 0; k < 100; k++) {
                for (let i = 0; i < allCardData.length; ++i) {
                    let random = Math.floor(Math.random() * allCardData.length);
                    let tmp = allCardData[i];
                    allCardData[i] = allCardData[random];
                    allCardData[random] = tmp;
                }
            }
            //获取手牌长度
            let DataArrlength = handCardDataArr.length;
            //获取新的牌
            let allCard = allCardData.splice(0, cardCount - DataArrlength);
            //拼接数组
            handCardDataArr = handCardDataArr.concat(allCard);
            //排序
            handCardDataArr.sort((a, b) => {
                return this.gameLogic.getCardLogicValue(b) - this.gameLogic.getCardLogicValue(a)
            });
            //分析
            let cardTypeResultArr = this.analyseOutCardTypeActive(handCardDataArr);
            // 炸弹
            if (cardTypeResultArr[gameProto.cardType.BOMB_CARD].cardTypeCount >= handCardDat.ZhaDan && handCardDat.ZhaDan > 0 && handCardlist.ZhaDan.length != handCardDat.ZhaDan) {
                let cardarr = cardTypeResultArr[gameProto.cardType.BOMB_CARD].cardDataArr;
                for (let index = 0; index < cardarr.length; index++) {
                    let lincardarr = cardarr[index];
                    if (handCardlist.ZhaDan.length == handCardDat.ZhaDan) {
                        break;
                    }
                    if (this.IncludeshandCardDat(handCardlist, lincardarr)) {
                        handCardlist.ZhaDan.push(lincardarr);
                        handCardDataArr = this.DelehandCardDat(handCardlist, handCardDataArr);
                        cardTypeResultArr = this.analyseOutCardTypeActive(handCardDataArr);
                    }
                }
            }
            // 顺子
            if (!isHaoHuai) {
                //顺子J以下
                if (cardTypeResultArr[gameProto.cardType.SINGLE_LINE].cardTypeCount != handCardDat.ShunZi) {
                    let cardarr = cardTypeResultArr[gameProto.cardType.SINGLE_LINE].cardDataArr;
                    for (let index = 0; index < cardarr.length; index++) {
                        let lincardarr = cardarr[index];
                        if (this.gameLogic.getCardLogicValue(lincardarr[cardarr.length - 1]) > 11) {
                            if (handCardDataArr.indexOf(lincardarr[lincardarr.length - 1]) != -1) {
                                let Arr = handCardDataArr.splice(handCardDataArr.indexOf(lincardarr[lincardarr.length - 1]), 1);
                                allCardData.push(Arr[0]);
                                cardTypeResultArr = this.analyseOutCardTypeActive(handCardDataArr);
                            }
                        } else if (cardTypeResultArr[gameProto.cardType.SINGLE_LINE].cardTypeCount != handCardDat.ShunZi) {
                            let sum = utils.getRandomNum(0, cardarr.length - 1);
                            if (handCardDataArr.indexOf(cardarr[sum]) != -1) {
                                let Arr = handCardDataArr.splice(handCardDataArr.indexOf(cardarr[sum]), 1);
                                allCardData.push(Arr[0]);
                                cardTypeResultArr = this.analyseOutCardTypeActive(handCardDataArr);
                            }
                        }
                    }
                }
            }
            if (cardTypeResultArr[gameProto.cardType.SINGLE_LINE].cardTypeCount >= handCardDat.ShunZi && handCardDat.ShunZi > 0 && handCardlist.ShunZi.length != handCardDat.ShunZi) {
                let cardarr = cardTypeResultArr[gameProto.cardType.SINGLE_LINE].cardDataArr;
                for (let index = 0; index < cardarr.length; index++) {
                    let lincardarr = cardarr[index];
                    if (handCardlist.ShunZi.length == handCardDat.ShunZi) {
                        break;
                    }
                    if (this.IncludeshandCardDat(handCardlist, lincardarr)) {
                        handCardlist.ShunZi.push(lincardarr);
                        handCardDataArr = this.DelehandCardDat(handCardlist, handCardDataArr);
                        cardTypeResultArr = this.analyseOutCardTypeActive(handCardDataArr);
                    }
                }
            }
            //三带
            if (!isHaoHuai) {
                //三张9, 以下的
                if (cardTypeResultArr[gameProto.cardType.THREE_LINE].cardTypeCount >= handCardDat.SanZhang) {
                    let cardarr = cardTypeResultArr[gameProto.cardType.THREE_LINE].cardDataArr;
                    for (let index = 0; index < cardarr.length; index++) {
                        let lincardarr = cardarr[index];
                        if (this.gameLogic.getCardLogicValue(lincardarr[cardarr.length - 1]) >= 9) {
                            let sum = utils.getRandomNum(0, lincardarr.length - 1);
                            if (handCardDataArr.indexOf(lincardarr[sum]) != -1) {
                                let Arr = handCardDataArr.splice(handCardDataArr.indexOf(lincardarr[sum]), 1);
                                allCardData.push(Arr[0]);
                                cardTypeResultArr = this.analyseOutCardTypeActive(handCardDataArr);
                            }
                        } else if (cardTypeResultArr[gameProto.cardType.THREE_LINE].cardTypeCount > handCardDat.ShunZi) {
                            let sum = utils.getRandomNum(0, cardarr.length - 1);
                            if (handCardDataArr.indexOf(cardarr[sum]) != -1) {
                                let Arr = handCardDataArr.splice(handCardDataArr.indexOf(cardarr[sum]), 1);
                                allCardData.push(Arr[0]);
                                cardTypeResultArr = this.analyseOutCardTypeActive(handCardDataArr);
                            }
                        }
                    }
                }
            }
            if (cardTypeResultArr[gameProto.cardType.THREE_LINE].cardTypeCount >= handCardDat.SanZhang && handCardDat.SanZhang > 0 && handCardlist.SanZhang.length != handCardDat.SanZhang) {
                let cardarr = cardTypeResultArr[gameProto.cardType.THREE_LINE].cardDataArr;
                for (let index = 0; index < cardarr.length; index++) {
                    let lincardarr = cardarr[index];
                    if (handCardlist.SanZhang.length == handCardDat.SanZhang) {
                        break;
                    }
                    if (this.IncludeshandCardDat(handCardlist, lincardarr)) {
                        handCardlist.SanZhang.push(lincardarr);
                        handCardDataArr = this.DelehandCardDat(handCardlist, handCardDataArr);
                        cardTypeResultArr = this.analyseOutCardTypeActive(handCardDataArr);
                    }
                }
            }

            if (!isHaoHuai) {
                //对子J以下的
                let DOUEArr = [];
                let cardarr = cardTypeResultArr[gameProto.cardType.DOUBLE].cardDataArr;
                for (let i = 0; i < cardarr.length; i++) {
                    if (this.gameLogic.getCardLogicValue(cardarr[i]) >= 11 && !handCardlist.includes(cardarr[i])) {
                        DOUEArr.push(cardarr[i]);
                    }
                }
                for (let key = 0; key < DOUEArr.length; key++) {
                    if (cardTypeResultArr[gameProto.cardType.DOUBLE].cardTypeCount <= handCardDat.DuiZi) {
                        continue;
                    }
                    let Arr = handCardDataArr.splice(handCardDataArr.indexOf(DOUEArr[DOUEArr.length - 1]), 1);
                    allCardData.push(Arr[0]);
                    cardTypeResultArr = this.analyseOutCardTypeActive(handCardDataArr);
                }
            }
            if (cardTypeResultArr[gameProto.cardType.DOUBLE].cardTypeCount >= handCardDat.DuiZi && handCardDat.DuiZi > 0 && handCardlist.DuiZi.length != handCardDat.DuiZi) {
                let cardarr = cardTypeResultArr[gameProto.cardType.DOUBLE].cardDataArr;
                for (let index = 0; index < cardarr.length; index++) {
                    let lincardarr = cardarr[index];
                    if (handCardlist.DuiZi.length == handCardDat.DuiZi) {
                        break;
                    }
                    if (this.IncludeshandCardDat(handCardlist, lincardarr)) {
                        handCardlist.DuiZi.push(lincardarr);
                        handCardDataArr = this.DelehandCardDat(handCardlist, handCardDataArr);
                        cardTypeResultArr = this.analyseOutCardTypeActive(handCardDataArr);
                    }
                }
            }
            let lindanShu = handCardDataArr.slice();
            for (let key = 0; key < cardTypeResultArr.length; key++) {
                let cardTypeCount = cardTypeResultArr[key].cardTypeCount;
                let cardType = cardTypeResultArr[key].cardType;
                //不计算三带1-三带2-四带X
                if (cardTypeCount != 0 && cardType >= gameProto.cardType.THREE_LINE_TAKE_ONE && cardType <= gameProto.cardType.FOUR_LINE_TAKE_X) {
                    continue;
                }
                if (cardTypeCount != 0 && cardType >= gameProto.cardType.DOUBLE && cardType <= gameProto.cardType.TIAN_BOMB) {
                    //删除临时手牌中的牌
                    for (let key_tow in cardTypeResultArr[key].cardDataArr) {
                        for (let key_on = 0; key_on < cardTypeResultArr[key].cardDataArr[key_tow].length; key_on++) {
                            let lincardDataArr = cardTypeResultArr[key].cardDataArr[key_tow][key_on];
                            if (lindanShu.includes(lincardDataArr)) {
                                lindanShu.splice(lindanShu.indexOf(lincardDataArr), 1);
                            }
                        }
                    }
                }
            }
            if (!isHaoHuai) {
                //单牌K以下的， 不连续的
                let DOUBLEArr = [];
                for (let i = 0; i < lindanShu.length; i++) {
                    if (this.gameLogic.getCardLogicValue(lindanShu[i]) <= 13) {
                        DOUBLEArr.push(lindanShu[i]);
                    } else if (this.gameLogic.getCardLogicValue(lindanShu[i]) > 13) {
                        let Arr = handCardDataArr.splice(handCardDataArr.indexOf(lindanShu[i]), 1);
                        allCardData.push(Arr[0]);
                        cardTypeResultArr = this.analyseOutCardTypeActive(handCardDataArr);
                    }
                }
                let linDOUBLEArr = [];
                for (let index = 0; index < handCardDat.DanPai.length; index++) {
                    linDOUBLEArr = linDOUBLEArr.concat(handCardDat.DanPai[index]);

                }
                linDOUBLEArr = linDOUBLEArr.concat(DOUBLEArr);
                let lincardTypeResultArr = this.analyseOutCardTypeActive(linDOUBLEArr);
                //检测是否有顺子如果有随机扔出一张牌
                if (lincardTypeResultArr[gameProto.cardType.SINGLE_LINE].cardTypeCount > 0) {
                    let cardarr = lincardTypeResultArr[gameProto.cardType.SINGLE_LINE].cardDataArr;
                    for (let index = 0; index < cardarr.length; index++) {
                        let sum = utils.getRandomNum(0, cardarr.length - 1);
                        if (handCardDataArr.indexOf(cardarr[sum]) != -1) {
                            let Arr = handCardDataArr.splice(handCardDataArr.indexOf(cardarr[sum]), 1);
                            allCardData.push(Arr[0]);
                            lincardTypeResultArr = this.analyseOutCardTypeActive(handCardDataArr);
                        }
                        if (DOUBLEArr.indexOf(cardarr[sum]) != -1) {
                            let Arr = DOUBLEArr.splice(DOUBLEArr.indexOf(cardarr[sum]), 1);
                        }
                    }
                }
                if (DOUBLEArr.length != handCardDat.DanPai) {
                    let linDOUBLEArr = DOUBLEArr.length;
                    for (let index = 0; index < DOUBLEArr.length; index++) {
                        if (linDOUBLEArr <= handCardDat.DanPai) {
                            continue;
                        }
                        linDOUBLEArr--;
                        let sum = utils.getRandomNum(0, DOUBLEArr.length - 1);
                        let Arr = handCardDataArr.splice(handCardDataArr.indexOf(DOUBLEArr[sum]), 1);
                        allCardData.push(Arr[0]);
                        cardTypeResultArr = this.analyseOutCardTypeActive(handCardDataArr);
                    }

                }
            }
            if (cardTypeResultArr[gameProto.cardType.SINGLE].cardTypeCount >= handCardDat.DanPai && handCardDat.DanPai > 0 && handCardlist.DanPai.length != handCardDat.DanPai) {
                let cardarr = cardTypeResultArr[gameProto.cardType.SINGLE].cardDataArr;
                for (let index = 0; index < cardarr.length; index++) {
                    let lincardarr = cardarr[index];
                    if (handCardlist.DanPai.length == handCardDat.DanPai) {
                        break;
                    }
                    if (this.IncludeshandCardDat(handCardlist, lincardarr)) {
                        handCardlist.DanPai.push(lincardarr);
                        handCardDataArr = this.DelehandCardDat(handCardlist, handCardDataArr);
                        cardTypeResultArr = this.analyseOutCardTypeActive(handCardDataArr);
                    }
                }
            }
            for (let key in handCardlist) {
                if (handCardlist[key].length == handCardDat[key]) {
                    linwarningSum = true;
                } else {
                    linwarningSum = false;
                    break;
                }
            }
            if (linwarningSum) {
                warningSum = 520;
            } else {
                handCardDataArr = this.DelehandCardDat(handCardlist, handCardDataArr);
                for (let index = 0; index < handCardDataArr.length; index++) {
                    let Arr = handCardDataArr.splice(handCardDataArr.indexOf(handCardDataArr[index]), 1);
                    allCardData.push(Arr[0]);
                }
            }
            if (warningSum >= 500) {
                let i = 0;
            }

        }
        while (handCardDataArr.length != cardCount && warningSum <= 500)
        //写入最新的手牌
        handCardDataArr = [];
        for (let key in handCardlist) {
            for (let key_on = 0; key_on < handCardlist[key].length; key_on++) {
                //拼接数组
                handCardDataArr = handCardDataArr.concat(handCardlist[key][key_on]);
            }
        }
        //获取不够长度的牌
        let allCard = allCardData.splice(0, cardCount - handCardDataArr.length);
        //拼接数组
        handCardDataArr = handCardDataArr.concat(allCard);
        let cardTypeResultArr = [];
        cardTypeResultArr = this.analyseOutCardTypeActive(handCardDataArr);
        return handCardDataArr;
    }
    DelehandCardDat(handCardlist, handCardDataArr) {
        //删除已经使用过的数据
        for (let key in handCardlist) {
            for (let key_on = 0; key_on < handCardlist[key].length; key_on++) {
                for (let key_tow = 0; key_tow < handCardlist[key][key_on].length; key_tow++) {
                    if (handCardDataArr.includes(handCardlist[key][key_on][key_tow])) {
                        let Arr = handCardDataArr.splice(handCardDataArr.indexOf(handCardlist[key][key_on][key_tow]), 1);
                    }
                }
            }
        }
        return handCardDataArr;
    }
    IncludeshandCardDat(handCardlist, lincardarr) {
        //查询同牌是否已经使用过 //防止出现
        for (let key in handCardlist) {
            for (let key_on = 0; key_on < handCardlist[key].length; key_on++) {
                for (let key_tow = 0; key_tow < handCardlist[key][key_on].length; key_tow++) {
                    let cardarr = lincardarr.filter(item => this.gameLogic.getCardLogicValue(item) == this.gameLogic.getCardLogicValue(handCardlist[key][key_on][key_tow]));
                    if (cardarr.length != 0) {
                        return false;
                    }
                }
            }
        }
        return true;
    }
    sortCardList(cardDataArr, isOrderByCount) {
        //数目过虑
        if (!cardDataArr || cardDataArr.length <= 1) return cardDataArr;
        let cardCount = cardDataArr.length;
        //转换数值
        let sortValueArr = [];
        for (let i = 0; i < cardDataArr.length; i++) {
            sortValueArr[i] = this.gameLogic.getCardLogicValue(cardDataArr[i]);
        }
        //排序操作
        for (let i = 0; i < cardCount; ++i) {
            let sortValue = sortValueArr[i];
            let cardData = cardDataArr[i];
            for (let j = i + 1; j < cardCount; ++j) {
                if ((sortValueArr[j] > sortValue) || ((sortValue === sortValueArr[j]) && (cardDataArr[j] > cardData))) {
                    // 交换位置]
                    sortValueArr[i] = sortValueArr[j];
                    sortValueArr[j] = sortValue;
                    sortValue = sortValueArr[i];
                    cardDataArr[i] = cardDataArr[j];
                    cardDataArr[j] = cardData;
                    cardData = cardDataArr[i];
                }
            }
        }
        //数目排序
        if (!!isOrderByCount) {
            //分析扑克
            let analyseResult = this.gameLogic.analyseCardDataArr(cardDataArr);

            cardDataArr = [];
            //拷贝四牌
            cardDataArr = cardDataArr.concat(analyseResult.fourCardData);
            //拷贝三牌
            cardDataArr = cardDataArr.concat(analyseResult.threeCardData);
            //拷贝对牌
            cardDataArr = cardDataArr.concat(analyseResult.doubleCardData);
            //拷贝单牌
            cardDataArr = cardDataArr.concat(analyseResult.singleCardData);
        }
        return cardDataArr;
    };
    removeCard(removeCardArr, cardDataArr) {
        if (removeCardArr.length > cardDataArr.length) return false;

        let tempCardDataArr = cardDataArr.slice();

        //置零扑克
        let deleteCount = 0;
        for (let i = 0; i < removeCardArr.length; i++) {
            for (let j = 0; j < cardDataArr.length; j++) {
                if (removeCardArr[i] === tempCardDataArr[j]) {
                    tempCardDataArr[j] = 0;
                    deleteCount++;
                    break;
                }
            }
        }
        if (deleteCount !== removeCardArr.length) return false;

        let index = 0;
        for (let i = 0; i < tempCardDataArr.length; ++i) {
            if (tempCardDataArr[i] !== 0) {
                cardDataArr[index++] = tempCardDataArr[i];
            }
        }
        cardDataArr.splice(index, cardDataArr.length - index);
        return true;
    };
    reSortCard(allUserCardArr, robotArr) {
        let robotCount = 0;
        for (let i = 0; i < robotArr.length; ++i) {
            if (robotArr[i]) {
                robotCount++;
                break;
            }
        }
        if (robotCount === 0 || robotCount === 3) return;
        let tmp;
        if (robotCount === 1) {
            tmp = 0;
        } else {
            tmp = 4;
        }
        let index = 0;
        for (let i = 0; i < allUserCardArr.length; ++i) {
            let score = this.landScore(i, 0, allUserCardArr);
            if (robotCount === 1) {
                if (score > tmp) {
                    tmp = score;
                    index = i;
                }
            } else {
                if (score < tmp) {
                    tmp = score;
                    index = i;
                }
            }
        }
        // 将最大的牌给机器人
        if (robotCount === 1) {
            for (let i = 0; i < robotArr.length; ++i) {
                if (!!robotArr[i]) {
                    if (index === i) return;
                    let temp = allUserCardArr[i];
                    allUserCardArr[i] = allUserCardArr[index];
                    allUserCardArr[index] = temp;
                }
            }
        }
        // 最小的牌个玩家
        else {
            for (let i = 0; i < robotArr.length; ++i) {
                if (!robotArr[i]) {
                    if (index === i) return;
                    let temp = allUserCardArr[i];
                    allUserCardArr[i] = allUserCardArr[index];
                    allUserCardArr[index] = temp;
                }
            }
        }
    };

    landScore(meChairID, currentLandScore, allUserCardDataArr) {
        //大牌数目
        let largeCardCount = 0;
        let index = 0;
        let cardDataArr = allUserCardDataArr[meChairID];
        while (index < cardDataArr.length) {
            if (this.gameLogic.getCardLogicValue(cardDataArr[index]) >= 15) ++largeCardCount;
            index++;
        }

        //单牌个数
        let singleCardCount = this.analyseSingleCardCount(cardDataArr, null);

        // 获取炸弹数量
        let allBombCard = getAllBombCard(cardDataArr);
        let bombCount = Math.ceil(allBombCard.length / 4);

        //叫3分
        if (largeCardCount + bombCount >= 4 && singleCardCount <= 4) {
            return 3;
        }
        //叫2分
        if (largeCardCount + bombCount >= 3 && currentLandScore <= 5 && currentLandScore < 2) return 2;

        // 叫1分
        if (largeCardCount + bombCount >= 2 && currentLandScore <= 5 && currentLandScore < 1) return 1;

        //放弃叫分
        return 0;
    };
    //出牌搜索
    //庄家uid 赢家uid 所有玩家牌 上轮出牌
    searchOutCard(bankerUid, winUid, handCards, lastOperateCards = [], linuserList) {
        //模拟次数 
        this.baoDanUser = []; //报单玩家
        this.userList = JSON.parse(JSON.stringify(linuserList));
        let simulationFrequency = 100;
        let CardsList = {};
        //获取下一位玩家
        let nextCards = this.OutCarlastOperate(winUid);
        //下一位玩家手牌为1
        if (handCards[nextCards].length == 1) {
            //报单玩家
            this.baoDanUser.push(nextCards);
        }
        for (let key in handCards) {
            CardsList[key] = {};
        }
        //模拟出牌 
        for (let win = 0; win < simulationFrequency; win++) {
            //出牌
            let linHandCards = JSON.parse(JSON.stringify(handCards));
            this.curOperateUid = winUid; //当前操作玩家
            this.lastOperateUid = bankerUid ? bankerUid : winUid; //最后一个出牌的玩家
            bankerUid = bankerUid ? bankerUid : winUid; //最后一个出牌的玩家
            let OUTValue = 0; //出牌数量
            this.MCTS(bankerUid, winUid, linHandCards, lastOperateCards, CardsList, null, OUTValue, handCards[winUid].length);

            // 出现90%的胜率或者90%的选择，提前end
            if ((win + 1) % 30 == 0) {
                let maxv = 0;
                let maxn = 0;
                let maxz = 0;
                for (let key in CardsList[winUid]) {
                    let s = CardsList[winUid][key];
                    if (s.stepNumber > maxn) {
                        maxn = s.stepNumber;
                    }
                    if (s.visitFrequency > maxn) {
                        maxz = s.visitFrequency;
                    }
                    if (s.CardsValue > maxv) {
                        maxv = s.CardsValue;
                    }
                }
                //|| (maxn / maxz) * 90 / 100 > 0.9
                if (maxn > win * 90 / 100 || maxv > win * 90 / 100) {
                    break;
                }

            }
        }
        //记录是否有赢的次数
        let isCardsList = false;
        let win = [];
        this.maxList = {};
        for (let key in CardsList[winUid]) {
            let s = CardsList[winUid][key];
            //访问次数大于赢的次数 ：假设进入10次 10次全赢即为必赢
            if (s.visitFrequency > s.stepNumber) {
                win.push(s);
            }
            //有赢的次数
            if (s.stepNumber > 0) {
                isCardsList = true;
            }
        }
        let resultCard = [];
        if (win.length == 0) {
            // 必赢
            resultCard = this.MCTSSelectByWin(handCards[winUid], CardsList[winUid], lastOperateCards);
        } else if (isCardsList == false) {
            // 必输
            resultCard = this.MCTSSelectByLose(handCards[winUid], CardsList[winUid], lastOperateCards);
        } else {
            // 同value的权重计算，选个价值最低的打出去
            resultCard = this.MCTSSelect(handCards[winUid], CardsList[winUid], lastOperateCards);
        }
        if (resultCard == null) {
            for (let key in CardsList[winUid]) {
                //判断出牌是否符合规则
                let result = {
                    isSuccess: true,
                    errMsg: null
                };
                if (lastOperateCards && lastOperateCards.length != 0) {
                    result = this.gameLogic.compareCard(CardsList[winUid][key].resultCard, lastOperateCards, this.gameRule)
                }
                //如果有报单
                if (this.baoDanUser.length > 0) {
                    let cardType = this.gameLogic.getCardType(CardsList[winUid][key].resultCard, this.gameRule);
                    if (cardType == gameProto.cardType.SINGLE && handCards[winUid].find(item => this.gameLogic.getCardLogicValue(item) > this.gameLogic.getCardLogicValue(CardsList[winUid][key].resultCard[0]))) {
                        result.isSuccess = false;
                    }
                }
                if (!this.gameRule.chaizhadan && this.gameLogic.isChaiZhaDan(CardsList[winUid][key].resultCard, handCards[winUid])) {
                    result.isSuccess = false;
                }
                if (result.isSuccess) {
                    resultCard = CardsList[winUid][key].resultCard.slice()
                    break;
                }
            }
        }
        return resultCard;
    };
    MCTSSelectByWin(handCards, CardsList, lastOperateCards = []) {
        let cardinfo = null;

        for (let key in CardsList) {
            //判断出牌是否符合规则
            let result = {
                isSuccess: true,
                errMsg: null
            };
            if (lastOperateCards && lastOperateCards.length != 0) {
                result = this.gameLogic.compareCard(CardsList[key].resultCard, lastOperateCards, this.gameRule)
            }
            //判断拆炸弹没有
            if (!this.gameRule.chaizhadan && this.gameLogic.isChaiZhaDan(CardsList[key].resultCard, handCards)) {
                result.isSuccess = false;
            }
            //如果有报单
            if (this.baoDanUser.length > 0) {
                let cardType = this.gameLogic.getCardType(CardsList[key].resultCard, this.gameRule);
                if (cardType == gameProto.cardType.SINGLE && handCards.find(item => this.gameLogic.getCardLogicValue(item) > this.gameLogic.getCardLogicValue(CardsList[key].resultCard[0]))) {
                    result.isSuccess = false;
                }
            }
            if (result.isSuccess) {
                if (JSON.stringify(this.maxList) == '{}') {
                    cardinfo = CardsList[key].resultCard.slice();
                    this.maxList = JSON.parse(JSON.stringify(CardsList[key]));
                }
                let linOUTValue = this.maxList.OUTValue / this.maxList.visitFrequency;
                let linCardsList = CardsList[key].OUTValue / this.maxList.visitFrequency;
                if (CardsList[key].Weight <= this.maxList.Weight && linOUTValue > linCardsList) {
                    cardinfo = CardsList[key].resultCard.slice();
                    this.maxList = JSON.parse(JSON.stringify(CardsList[key]));
                }
                if (this.baoDanUser.length > 0 && cardinfo == null) {
                    cardinfo = CardsList[key].resultCard.slice();
                    this.maxList = JSON.parse(JSON.stringify(CardsList[key]));
                }
            }
        }
        if (cardinfo == null && JSON.stringify(this.maxList) != '{}') {
            cardinfo = JSON.parse(JSON.stringify(this.maxList.resultCard.slice()));
            for (let key in CardsList) {
                let isSuccess = true;
                //判断拆炸弹没有
                if (!this.gameRule.chaizhadan && this.gameLogic.isChaiZhaDan(CardsList[key].resultCard, handCards)) {
                    isSuccess = false;
                }
                if (CardsList[key].CardsValue > this.maxList.CardsValue && isSuccess) {
                    cardinfo = CardsList[key].resultCard.slice();
                    this.maxList = JSON.parse(JSON.stringify(CardsList[key]));
                } else if (CardsList[key].Weight <= this.maxList.Weight && CardsList[key].CardsValue == this.maxList.CardsValue) {
                    cardinfo = CardsList[key].resultCard.slice();
                    this.maxList = JSON.parse(JSON.stringify(CardsList[key]));
                }
            }
        }
        return cardinfo;
    }
    MCTSSelectByLose(handCards, CardsList, lastOperateCards = []) {
        let cardinfo = null;
        for (let key in CardsList) {

            //判断出牌是否符合规则
            let result = {
                isSuccess: true,
                errMsg: null
            };
            if (lastOperateCards && lastOperateCards.length != 0) {
                result = this.gameLogic.compareCard(CardsList[key].resultCard, lastOperateCards, this.gameRule)
            }
            //如果有报单
            if (this.baoDanUser.length > 0) {
                let cardType = this.gameLogic.getCardType(CardsList[key].resultCard, this.gameRule);
                if (cardType == gameProto.cardType.SINGLE && handCards.find(item => this.gameLogic.getCardLogicValue(item) > this.gameLogic.getCardLogicValue(CardsList[key].resultCard[0]))) {
                    result.isSuccess = false;
                }
            }
            //判断拆炸弹没有
            if (!this.gameRule.chaizhadan && this.gameLogic.isChaiZhaDan(CardsList[key].resultCard, handCards)) {
                result.isSuccess = false;
            }
            if (result.isSuccess) {
                let cardType = this.gameLogic.getCardType(CardsList[key].resultCard, this.gameRule);
                if (cardType == gameProto.cardType.BOMB_CARD || cardType == gameProto.cardType.TIAN_BOMB) {
                    if (!lastOperateCards || lastOperateCards.length == 0 || JSON.stringify(this.maxList) != '{}') {
                        continue;
                    }
                }
                if (JSON.stringify(this.maxList) == '{}') {
                    this.maxList = JSON.parse(JSON.stringify(CardsList[key]));
                }
                //最长 牌值保存比较小
                let CardsValue = CardsList[key].CardsValue - this.maxList.CardsValue + 1;
                let linOUTValue = this.maxList.OUTValue / this.maxList.visitFrequency;
                let linCardsList = CardsList[key].OUTValue / this.maxList.visitFrequency;
                if (linCardsList >= linOUTValue && CardsList[key].CardsValue != this.maxList.CardsValue) { //长度不一样时 取出牌回合最少
                    cardinfo = CardsList[key].resultCard.slice();
                    this.maxList = JSON.parse(JSON.stringify(CardsList[key]));
                } else if (CardsList[key].Weight <= this.maxList.Weight && CardsList[key].CardsValue == this.maxList.CardsValue) { //长度一样 取收出牌权重小的
                    cardinfo = CardsList[key].resultCard.slice();
                    this.maxList = JSON.parse(JSON.stringify(CardsList[key]));
                }
                if (this.baoDanUser.length > 0 && cardinfo == null) {
                    cardinfo = CardsList[key].resultCard.slice();
                    this.maxList = JSON.parse(JSON.stringify(CardsList[key]));
                }
            }
        }
        if (cardinfo == null && JSON.stringify(this.maxList) != '{}') {
            cardinfo = JSON.parse(JSON.stringify(this.maxList.resultCard.slice()));
            for (let key in CardsList) {
                let isSuccess = true;
                if (!this.gameRule.chaizhadan && this.gameLogic.isChaiZhaDan(CardsList[key].resultCard, handCards)) {
                    isSuccess = false;
                }
                if (CardsList[key].linValue > this.maxList.linValue && isSuccess) {
                    cardinfo = CardsList[key].resultCard.slice();
                    this.maxList = JSON.parse(JSON.stringify(CardsList[key]));
                }
            }
        }
        return cardinfo;
    }
    MCTSSelect(handCards, CardsList, lastOperateCards = []) {
        let cardinfo = null;
        let linCardsList = {};
        let isCardsList = false;
        for (let key in CardsList) {
            if (CardsList[key].stepNumber > 0) {
                linCardsList[key] = JSON.parse(JSON.stringify(CardsList[key]));
                isCardsList = true;
            }
        }
        if (isCardsList) {
            CardsList = JSON.parse(JSON.stringify(linCardsList));
        }
        for (let key in CardsList) {

            //判断出牌是否符合规则
            let result = {
                isSuccess: true,
                errMsg: null
            };
            if (lastOperateCards && lastOperateCards.length != 0) {
                result = this.gameLogic.compareCard(CardsList[key].resultCard, lastOperateCards, this.gameRule)
            }
            //如果有报单
            if (this.baoDanUser.length > 0) {
                let cardType = this.gameLogic.getCardType(CardsList[key].resultCard, this.gameRule);
                if (cardType == gameProto.cardType.SINGLE && handCards.find(item => this.gameLogic.getCardLogicValue(item) > this.gameLogic.getCardLogicValue(CardsList[key].resultCard[0]))) {
                    result.isSuccess = false;
                }
            }
            //判断拆炸弹没有
            if (!this.gameRule.chaizhadan && this.gameLogic.isChaiZhaDan(CardsList[key].resultCard, handCards)) {
                result.isSuccess = false;
            }
            if (result.isSuccess) {
                if (JSON.stringify(this.maxList) == '{}') {
                    this.maxList = JSON.parse(JSON.stringify(CardsList[key]));
                }
                if (lastOperateCards && lastOperateCards.length == 0 && CardsList[key].resultCard == 4 && this.gameLogic.isBoom(CardsList[key].resultCard)) {
                    continue;
                }
                let CardsValue = CardsList[key].CardsValue - this.maxList.CardsValue + 1;
                let linOUTValue = this.maxList.OUTValue / this.maxList.visitFrequency;
                let linCardsList = CardsList[key].OUTValue / this.maxList.visitFrequency;

                if (linCardsList <= linOUTValue && CardsList[key].CardsValue != this.maxList.CardsValue) { //长度不一样时 取出牌回合最少
                    if (CardsList[key].CardsValue > this.maxList.CardsValue) {
                        cardinfo = CardsList[key].resultCard.slice();
                        this.maxList = JSON.parse(JSON.stringify(CardsList[key]));
                    } else if (CardsList[key].CardsValue < this.maxList.CardsValue && CardsList[key].linValue > this.maxList.linValue) {
                        cardinfo = CardsList[key].resultCard.slice();
                        this.maxList = JSON.parse(JSON.stringify(CardsList[key]));
                    }
                } else if (CardsList[key].Weight <= this.maxList.Weight && CardsList[key].CardsValue == this.maxList.CardsValue) { //长度一样 取收出牌权重小的
                    cardinfo = CardsList[key].resultCard.slice();
                    this.maxList = JSON.parse(JSON.stringify(CardsList[key]));
                } else if (CardsList[key].linValue > 0 && CardsList[key].linValue > this.maxList.linValue && CardsList[key].CardsValue == this.maxList.CardsValue) { //长度一样 取收手牌保存值大的
                    cardinfo = CardsList[key].resultCard.slice();
                    this.maxList = JSON.parse(JSON.stringify(CardsList[key]));
                }
                if (this.baoDanUser.length > 0 && cardinfo == null) {
                    cardinfo = CardsList[key].resultCard.slice();
                    this.maxList = JSON.parse(JSON.stringify(CardsList[key]));
                }
            }
        }
        if (cardinfo == null && JSON.stringify(this.maxList) != '{}') {
            cardinfo = JSON.parse(JSON.stringify(this.maxList.resultCard.slice()));
            for (let key in CardsList) {
                let isSuccess = true;
                if (!this.gameRule.chaizhadan && this.gameLogic.isChaiZhaDan(CardsList[key].resultCard, handCards)) {
                    isSuccess = false;
                }
                if (CardsList[key].linValue > this.maxList.linValue && isSuccess) {
                    cardinfo = CardsList[key].resultCard.slice();
                    this.maxList = JSON.parse(JSON.stringify(CardsList[key]));
                }
            }
        }
        return cardinfo;
    }

    //递归计算 所有出牌可能性
    MCTS(bankerUid, winUid, handCards, lastOperateCards, CardsList, SouCards = null, OUTValue = 0, handSum = 0) {
        for (let key in handCards) {
            if (handCards[key].length == 0) {
                return {
                    uid: key,
                    hands: handCards,
                    winUserUid: key
                };
            }
        }
        lastOperateCards = lastOperateCards ? lastOperateCards : [];

        let Cards = JSON.parse(JSON.stringify(handCards));
        if (lastOperateCards.length != 0 && this.curOperateUid == this.lastOperateUid) {
            lastOperateCards = [];
            this.lastOperateUid = null;
        }

        //解析
        //let outlist = {};
        let cardTypeResultArr = [];
        let outlist = {
            cardCount: 0,
            resultCard: []
        };

        let linOperate = this.OutCarlastOperate(this.curOperateUid);
        let isBaoDan = (Cards[linOperate].length == 1) ? true : false;
        if (lastOperateCards.length == 0) {
            outlist = this.outCardActive(Cards[this.curOperateUid]);
            // outlist.resultCard = this.gameLogic.getAutoCard(Cards[this.curOperateUid], null, isBaoDan);
            outlist.cardCount = outlist.resultCard.length;
            cardTypeResultArr = this.analyseOutCardTypeActive(JSON.parse(JSON.stringify(handCards[this.curOperateUid])));
        } else {
            let ndexuid = this.OutCarlastOperate(this.curOperateUid);
            outlist = this.outCardPassive(Cards[this.curOperateUid], lastOperateCards, Cards[ndexuid]);
            //outlist.resultCard = this.gameLogic.getAutoCard(Cards[this.curOperateUid], lastOperateCards, isBaoDan);
            outlist.resultCard = outlist.resultCard ? outlist.resultCard : [];
            if (outlist.resultCard.length > 0) {
                outlist.cardCount = outlist.resultCard.length;
            }
            this.analyseOutCardTypePassive(Cards[this.curOperateUid], lastOperateCards, cardTypeResultArr);
        }
        //记录每次第一次出牌同时记录
        if (handSum == Cards[winUid].length && this.curOperateUid == winUid) {
            //首次出牌
            let linSouCards = [];
            for (let index = 0; index < outlist.resultCard.length; index++) {
                linSouCards.push(this.gameLogic.getCardLogicValue(outlist.resultCard[index]));
            }
            SouCards = linSouCards.join('');
            if (SouCards == null || SouCards == '') {
                SouCards = '0';
            }
            //查询出牌是否存在
            if (SouCards && CardsList[winUid][SouCards]) {
                //已存在 循环查询 300 放出一个最新的出牌
                let linKai = false;
                for (let key in cardTypeResultArr) {
                    if (key == '0') {
                        continue;
                    }
                    let lineCardDataArr = cardTypeResultArr[key].cardDataArr;
                    for (let index = 0; index < lineCardDataArr.length; index++) {
                        let linSouCards = [];
                        for (let indexkey = 0; indexkey < lineCardDataArr[index].length; indexkey++) {
                            linSouCards.push(this.gameLogic.getCardLogicValue(lineCardDataArr[index][indexkey]));
                        }
                        SouCards = linSouCards.join('');
                        if (SouCards && !CardsList[winUid][SouCards]) {
                            linKai = true;
                            outlist.resultCard = lineCardDataArr[index].slice();
                            outlist.cardCount = lineCardDataArr[index].length;
                            break;
                        }
                    }
                    if (linKai) {
                        break;
                    }
                }

            }
            if (SouCards && !CardsList[winUid][SouCards]) {
                CardsList[winUid][SouCards] = {};
                CardsList[winUid][SouCards].winUid = winUid; //赢家ID
                CardsList[winUid][SouCards].CardsValue = 0; //手牌数量
                CardsList[winUid][SouCards].stepNumber = 0; //赢的次数
                CardsList[winUid][SouCards].visitFrequency = 0; //访问次数
                CardsList[winUid][SouCards].UCTChoose = 0; //UCT数据
                CardsList[winUid][SouCards].Weight = 0; //出牌权重
                CardsList[winUid][SouCards].resultCard = outlist.resultCard.slice(); //手牌
                CardsList[winUid][SouCards].OUTValue = 0; //出牌手牌数量
            } else {
                let MaxUCTChoose = 0;
                let linkey = null;
                //获取MAXUCT
                for (let key in CardsList[winUid]) {
                    if (CardsList[winUid][key].UCTChoose > MaxUCTChoose && CardsList[winUid][key].UCTChoose != 0) {
                        MaxUCTChoose = CardsList[winUid][key].UCTChoose;
                    }
                }
                //使用UCT数据最少的那个
                for (let key in CardsList[winUid]) {
                    if (linkey == null) {
                        linkey = key;
                    }
                    if (CardsList[winUid][key].UCTChoose < MaxUCTChoose && CardsList[winUid][key].UCTChoose != 0) {
                        linkey = key;
                        MaxUCTChoose = CardsList[winUid][key].UCTChoose;
                    }
                }
                outlist.resultCard = CardsList[winUid][linkey].resultCard.slice();
                outlist.cardCount = CardsList[winUid][linkey].resultCard.length;
                SouCards = linkey;

            }
        }
        if (outlist.cardCount != 0) {
            //删除出牌
            let linSouCards = [];
            for (let key = 0; key < outlist.resultCard.length; key++) {
                Cards[this.curOperateUid].splice(Cards[this.curOperateUid].indexOf(outlist.resultCard[key]), 1);
                linSouCards.push(this.gameLogic.getCardLogicValue(outlist.resultCard[key]));
            }
            let sssCards = linSouCards.join('');
            if (this.curOperateUid == winUid) {
                CardsList[winUid][SouCards].OUTValue += outlist.resultCard.length;
            }
            //最后一个出牌玩家
            lastOperateCards = JSON.parse(JSON.stringify(outlist.resultCard));
            this.lastOperateUid = this.curOperateUid;

        }
        //获取下一位操作者
        this.curOperateUid = this.OutCarlastOperate(this.curOperateUid);
        let {
            uid,
            hands,
            winUserUid
        } = this.MCTS(this.curOperateUid, winUid, Cards, lastOperateCards, CardsList, SouCards, OUTValue, handSum);
        //递归回第一次出牌
        let linSouCards = [];
        for (let index = 0; index < lastOperateCards.length; index++) {
            linSouCards.push(this.gameLogic.getCardLogicValue(lastOperateCards[index]));
        }
        if (SouCards == linSouCards.join('')) {
            //访问次数
            CardsList[winUid][SouCards].visitFrequency++;
            if (winUserUid == winUid) {
                //赢次数
                CardsList[winUid][SouCards].stepNumber++;
            }
            if (CardsList[winUid][SouCards].linValue != 0) {
                CardsList[winUid][SouCards].CardsValue = (handCards[winUid].length - Cards[winUid].length);
                CardsList[winUid][SouCards].linValue = this.parseOutCardTypeNumericValue(JSON.parse(JSON.stringify(Cards[winUid])));
                CardsList[winUid][SouCards].Weight = this.OutCardsWeight(CardsList[winUid][SouCards].resultCard, handCards[winUid]);
                CardsList[winUid][SouCards].UCTChoose += CardsList[winUid][SouCards].stepNumber / (CardsList[winUid][SouCards].visitFrequency + 1e-6) + 1 *
                    (Math.sqrt(Math.log(500) / (CardsList[winUid][SouCards].visitFrequency + 1e-6))); //UCT数据
            }
        }
        if (winUserUid == winUid) {
            if (CardsList[winUid][SouCards].winUid == null) {
                CardsList[winUid][SouCards].winUid = winUid;
            }
            return {
                uid,
                hands,
                winUserUid
            }
        }
        return {
            uid,
            hands,
            winUserUid: uid
        }
    }
    //解析手牌值 返回一个最大值
    parseOutCardTypeNumericValue(Cards) {
        //解析剩余牌值
        let ResultArr = this.analyseOutCardTypeActive(JSON.parse(JSON.stringify(Cards)));
        let maxValue = 0; //最大牌值
        for (let key = ResultArr.length - 1; key > 0; key--) {
            let cardTypeCount = ResultArr[key].cardTypeCount;
            let cardType = ResultArr[key].cardType;
            let linValue = 0; //临时牌值
            let lindanShu = JSON.parse(JSON.stringify(Cards)); //临时手牌
            let linResultArr = []; //临时解析数据
            if (cardTypeCount != 0) {
                //获取牌组数据
                linValue += this.getcardDataArr(ResultArr[key].cardDataArr, lindanShu, cardType);
                linResultArr = this.analyseOutCardTypeActive(JSON.parse(JSON.stringify(lindanShu)));
                //使用删减后的数据再次循环
                for (let key_to = linResultArr.length - 1; key_to > 0; key_to--) {
                    cardTypeCount = linResultArr[key_to].cardTypeCount;
                    cardType = linResultArr[key_to].cardType;
                    if (cardTypeCount != 0) {
                        linValue += this.getcardDataArr(linResultArr[key_to].cardDataArr, lindanShu, cardType);
                        linResultArr = this.analyseOutCardTypeActive(JSON.parse(JSON.stringify(lindanShu)));
                        key_to = linResultArr.length - 1;
                    }
                }
            }
            if (maxValue < linValue) {
                maxValue = linValue;
            }
        }
        return maxValue;
    }
    //获取牌组数据
    getcardDataArr(cardDataArr, Cards, cardType) {
        let linResultArr = 0; //临时解析数据
        //删除临时手牌中的牌
        for (let key_tow in cardDataArr) {
            for (let key_on = 0; key_on < cardDataArr[key_tow].length; key_on++) {
                let lincardDataArr = cardDataArr[key_tow][key_on];
                if (Cards.includes(lincardDataArr)) {
                    Cards.splice(Cards.indexOf(lincardDataArr), 1);
                }
                linResultArr += this.gameLogic.getCardLogicValue(lincardDataArr);
            }
            break;
        }
        return (linResultArr * cardType);
    }
    //获取下一位出牌人 
    OutCarlastOperate(Uid) {
        let linkey = [];
        let linuid = 0;
        for (let key in this.userList) {
            if (this.userList[key].uid == Uid) {
                linuid = this.userList[key].chairID;
            }
            linkey.push(this.userList[key].uid);
        }

        for (let i = 1; i <= this.gameRule.maxPlayerCount; ++i) {
            let nextChairID = (linuid + i) % this.gameRule.maxPlayerCount;
            if (linkey[nextChairID] != Uid) {
                return linkey[nextChairID];
            }
        }
    }
    //获取出牌权重
    OutCardsWeight(resultCard, handCards) {
        let {
            countList
        } = this.gameLogic.getCardsAndCount(handCards);
        let cardCount = 0;
        let lincard = null;
        let weight = 0;

        for (let i = 0; i < resultCard.length; i++) {
            for (let key in countList) {
                if (lincard != countList[key].card && countList[key].card == this.gameLogic.getCardLogicValue(resultCard[i])) {
                    cardCount += countList[key].count;
                    lincard = countList[key].card;
                    break;
                }
            }
            weight += this.gameLogic.getCardLogicValue(resultCard[i]);
        }
        return weight * cardCount;
    }
    //分析单牌
    getAllSingleCard(handCardDataArr) {
        let tmpCardDataArr = this.sortCardList(handCardDataArr.slice());
        let singleCardDataArr = [];
        //扑克分析
        for (let i = 0; i < handCardDataArr.length; i++) {
            //变量定义
            let sameCount = 1;
            let logicValue = this.gameLogic.getCardLogicValue(tmpCardDataArr[i]);
            //搜索同牌
            for (let j = i + 1; j < handCardDataArr.length; j++) {
                //获取扑克
                if (this.gameLogic.getCardLogicValue(tmpCardDataArr[j]) !== logicValue) break;
                //设置变量
                sameCount++;
                if (sameCount > 1) break;
            }
            if (sameCount === 1) singleCardDataArr.push(tmpCardDataArr[i]);

            //设置索引
            i += (sameCount - 1);
        }
        return singleCardDataArr;
    };

    //分析对子
    getAllDoubleCard(handCardDataArr) {
        let tmpCardDataArr = this.sortCardList(handCardDataArr.slice());
        let doubleCardDataArr = [];
        //扑克分析
        for (let i = 0; i < handCardDataArr.length; i++) {
            let sameCount = 1;
            let logicValue = this.gameLogic.getCardLogicValue(tmpCardDataArr[i]);

            for (let j = i + 1; j < handCardDataArr.length; ++j) {
                //搜索同牌
                if (this.gameLogic.getCardLogicValue(tmpCardDataArr[j]) !== logicValue) break;
                sameCount++;
            }
            if (sameCount >= 2) {
                doubleCardDataArr.push(tmpCardDataArr[i]);
                doubleCardDataArr.push(tmpCardDataArr[i + 1]);
            }
            i += (sameCount - 1);
        }
        return doubleCardDataArr;
    };

    //分析三条
    getAllThreeCard(handCardDataArr) {
        let tmpCardDataArr = this.sortCardList(handCardDataArr.slice());
        let threeCardDataArr = [];
        //扑克分析
        for (let i = 0; i < handCardDataArr.length - 2; i++) {
            let sameCount = 1;
            let logicValue = this.gameLogic.getCardLogicValue(tmpCardDataArr[i]);
            //搜索同牌
            for (let j = i + 1; j <= i + 3 && j < handCardDataArr.length; j++) {
                //获取扑克
                if (this.gameLogic.getCardLogicValue(tmpCardDataArr[j]) !== logicValue) break;
                sameCount++;
            }
            if (sameCount >= 3) {
                threeCardDataArr.push(tmpCardDataArr[i]);
                threeCardDataArr.push(tmpCardDataArr[i + 1]);
                threeCardDataArr.push(tmpCardDataArr[i + 2]);
            }
            i += (sameCount - 1);
        }
        return threeCardDataArr;
    };

    //分析顺子
    getAllLineCard(handCardDataArr) {
        let temCardDataArr = this.sortCardList(handCardDataArr.slice());
        let lineCardDataArr = [];
        //数据校验
        if (handCardDataArr.length < 5) return lineCardDataArr;
        let firstCard = 0;
        //去除2
        for (let i = 0; i < handCardDataArr.length; ++i) {
            if (this.gameLogic.getCardLogicValue(temCardDataArr[i]) < 15) {
                firstCard = i;
                break;
            }
        }
        let singleLineCardDataArr = [];
        let findSingleLine = true;
        //连牌判断
        while ((temCardDataArr.length + firstCard) >= 5 && findSingleLine) {
            findSingleLine = false;
            singleLineCardDataArr = [temCardDataArr[firstCard]];
            let lastCard = temCardDataArr[firstCard];
            for (let i = firstCard + 1; i < temCardDataArr.length; i++) {
                let cardData = temCardDataArr[i];
                let logicValueDiff = this.gameLogic.getCardLogicValue(lastCard) - this.gameLogic.getCardLogicValue(cardData);
                if (logicValueDiff > 0) {
                    lastCard = cardData;
                    // 非连续
                    if (logicValueDiff > 1) {
                        if (singleLineCardDataArr.length < 5) {
                            singleLineCardDataArr = [lastCard];
                        } else {
                            break;
                        }
                    }
                    // 连续
                    else {
                        singleLineCardDataArr.push(lastCard);
                    }
                }
            }
            //保存数据
            if (singleLineCardDataArr.length >= 5) {
                this.removeCard(singleLineCardDataArr, temCardDataArr);
                lineCardDataArr = lineCardDataArr.concat(singleLineCardDataArr);
                findSingleLine = true;
            }
        }
        return lineCardDataArr;
    };

    //分析炸弹
    getAllBombCard(handCardDataArr) {
        let boomCardArr = [];
        if (handCardDataArr.length < 4) return boomCardArr;
        //大小排序
        let temCardDataArr = this.sortCardList(handCardDataArr.slice());
        //扑克分析
        for (let i = 0; i < handCardDataArr.length - 3; i++) {
            //变量定义
            let sameCount = 1;
            let logicValue = this.gameLogic.getCardLogicValue(temCardDataArr[i]);
            //搜索同牌
            for (let j = i + 1; j <= i + 3 && j < handCardDataArr.length; j++) {
                //获取扑克
                if (this.gameLogic.getCardLogicValue(temCardDataArr[j]) !== logicValue) break;
                sameCount++;
            }
            if (sameCount === 4) {
                boomCardArr.push(temCardDataArr[i]);
                boomCardArr.push(temCardDataArr[i + 1]);
                boomCardArr.push(temCardDataArr[i + 2]);
                boomCardArr.push(temCardDataArr[i + 3]);
            }
        }
        return boomCardArr;
    };

    // 获取所有单张类型
    getAllSingleCardType(handCardDataArr, turnCardData) {
        let cardTypeResult = {
            cardType: gameProto.cardType.SINGLE,
            cardTypeCount: 0,
            cardDataArr: [],
            eachHandCardCount: [],
        };
        let handCardCount = handCardDataArr.length;
        for (let i = 0; i < handCardCount; ++i) {
            if (!!turnCardData && turnCardData.length > 0) {
                if (this.gameLogic.getCardLogicValue(handCardDataArr[i]) <= this.gameLogic.getCardLogicValue(turnCardData[0])) continue;
            }
            let index = cardTypeResult.cardTypeCount;
            cardTypeResult.cardDataArr[index] = [];
            cardTypeResult.cardType = gameProto.cardType.SINGLE;
            cardTypeResult.cardDataArr[index][0] = handCardDataArr[i];
            cardTypeResult.eachHandCardCount[index] = 1;
            cardTypeResult.cardTypeCount++;
        }
        return cardTypeResult;
    };

    // 获取所有对子类型
    getAllDoubleCardType(handCardDataArr, turnCardData) {
        let cardTypeResult = {
            cardType: gameProto.cardType.DOUBLE,
            cardTypeCount: 0,
            cardDataArr: [],
            eachHandCardCount: [],
        };
        let doubleCardDataArr = this.getAllDoubleCard(handCardDataArr);

        for (let i = 0; i < doubleCardDataArr.length; i += 2) {
            if (!!turnCardData && turnCardData.length > 0) {
                if (this.gameLogic.getCardLogicValue(doubleCardDataArr[i]) <= this.gameLogic.getCardLogicValue(turnCardData[0])) continue;
            }
            let index = cardTypeResult.cardTypeCount;
            cardTypeResult.cardDataArr[index] = [];
            cardTypeResult.cardType = gameProto.cardType.DOUBLE;
            cardTypeResult.cardDataArr[index][0] = doubleCardDataArr[i];
            cardTypeResult.cardDataArr[index][1] = doubleCardDataArr[i + 1];
            cardTypeResult.eachHandCardCount[index] = 2;
            cardTypeResult.cardTypeCount++;
        }
        return cardTypeResult;
    };

    // 获取单连类型
    getAllLineCardType(handCardDataArr, turnCardData) {
        let cardTypeResult = {
            cardType: gameProto.cardType.SINGLE_LINE,
            cardTypeCount: 0,
            cardDataArr: [],
            eachHandCardCount: [],
        };
        let turnFirstCardLogicValue = !turnCardData ? 0 : this.gameLogic.getCardLogicValue(turnCardData[0]);
        //恢复扑克，防止分析时改变扑克
        let tmpCardDataArr = this.sortCardList(handCardDataArr.slice());
        let handCardCount = tmpCardDataArr.length;
        let firstCard = 0;
        //去除2
        for (let i = 0; i < handCardCount; ++i) {
            if (this.gameLogic.getCardLogicValue(tmpCardDataArr[i]) < 15) {
                firstCard = i;
                break;
            }
        }
        let singleLineCardArr = [];
        let leftCardCount = handCardCount;
        let isFindSingleLine = true;

        //连牌判断
        while ((leftCardCount + firstCard) >= 5 && isFindSingleLine) {
            isFindSingleLine = false;
            let lastCard = tmpCardDataArr[firstCard];
            singleLineCardArr = [lastCard];
            for (let i = firstCard + 1; i < leftCardCount; i++) {
                let cardData = tmpCardDataArr[i];
                let logicValueDiff = this.gameLogic.getCardLogicValue(lastCard) - this.gameLogic.getCardLogicValue(cardData);
                if (logicValueDiff !== 0) {
                    lastCard = tmpCardDataArr[i];
                    if (logicValueDiff !== 1) {
                        //连续判断
                        if (singleLineCardArr.length < 5) {
                            singleLineCardArr = [lastCard]
                        } else break;
                    } else {
                        singleLineCardArr.push(lastCard);
                    }
                }
            }

            //保存数据
            if (singleLineCardArr.length >= 5 && (!turnCardData || (turnCardData.length <= singleLineCardArr.length))) {
                let index;
                //所有连牌
                let curLineCount = 5;
                let curLineIndex = 0;
                while (curLineCount <= singleLineCardArr.length) {
                    if (!!turnCardData && turnCardData.length > 0) {
                        if (curLineCount !== turnCardData.length) {
                            curLineIndex++;
                            if (curLineIndex + curLineCount > singleLineCardArr.length) {
                                curLineIndex = 0;
                                curLineCount++;
                            }
                            continue;
                        }
                        if (this.gameLogic.getCardLogicValue(singleLineCardArr[curLineIndex]) <= turnFirstCardLogicValue) {
                            curLineIndex = 0;
                            curLineCount++;
                            continue;
                        }
                    }
                    index = cardTypeResult.cardTypeCount;
                    if (!cardTypeResult.cardDataArr[index]) cardTypeResult.cardDataArr[index] = [];
                    cardTypeResult.cardType = gameProto.cardType.SINGLE_LINE;
                    cardTypeResult.cardDataArr[index] = singleLineCardArr.slice(curLineIndex, curLineIndex + curLineCount);
                    cardTypeResult.eachHandCardCount[index] = curLineCount;
                    cardTypeResult.cardTypeCount++;

                    curLineIndex++;
                    if (curLineIndex + curLineCount > singleLineCardArr.length) {
                        curLineIndex = 0;
                        curLineCount++;
                    }
                }

                this.removeCard(singleLineCardArr, tmpCardDataArr);
                leftCardCount -= singleLineCardArr.length;
                isFindSingleLine = true;
            }
        }
        return cardTypeResult;
    };

    // 获取对连类型
    getAllDoubleLineCardType(handCardDataArr, turnCardData) {
        let cardTypeResult = {
            cardType: gameProto.cardType.DOUBLE_LINE,
            cardTypeCount: 0,
            cardDataArr: [],
            eachHandCardCount: [],
        };

        let turnFirstCardLogicValue = !turnCardData ? 0 : this.gameLogic.getCardLogicValue(turnCardData[0]);

        //恢复扑克，防止分析时改变扑克
        let tmpCardDataArr = this.sortCardList(handCardDataArr.slice());
        let handCardCount = tmpCardDataArr.length;

        //连牌判断
        let firstCard = 0;
        //去除2
        for (let i = 0; i < handCardCount; ++i) {
            if (this.gameLogic.getCardLogicValue(tmpCardDataArr[i]) < 15) {
                firstCard = i;
                break;
            }
        }

        let leftCardCount = handCardCount - firstCard;
        let isFindDoubleLine = true;
        let doubleLineCount = 0;
        let doubleLineCard = [];
        //开始判断
        while (leftCardCount >= 4 && isFindDoubleLine) {
            let lastCard = tmpCardDataArr[firstCard];
            let sameCount = 1;
            doubleLineCount = 0;
            isFindDoubleLine = false;
            for (let i = firstCard + 1; i < leftCardCount + firstCard; ++i) {
                //搜索同牌
                while (this.gameLogic.getCardLogicValue(lastCard) === this.gameLogic.getCardLogicValue(tmpCardDataArr[i]) && i < leftCardCount + firstCard) {
                    ++sameCount;
                    ++i;
                }

                let lastDoubleCardValue = 0;
                if (doubleLineCount > 0) lastDoubleCardValue = this.gameLogic.getCardLogicValue(doubleLineCard[doubleLineCount - 1]);
                //重新开始
                if ((sameCount < 2 || (doubleLineCount > 0 && (lastDoubleCardValue - this.gameLogic.getCardLogicValue(lastCard)) !== 1)) && i <= leftCardCount + firstCard) {
                    if (doubleLineCount >= 4) break;
                    //回退
                    if (sameCount >= 2) i -= sameCount;
                    lastCard = tmpCardDataArr[i];
                    doubleLineCount = 0;
                }
                //保存数据
                else if (sameCount >= 2) {
                    doubleLineCard[doubleLineCount] = tmpCardDataArr[i - sameCount];
                    doubleLineCard[doubleLineCount + 1] = tmpCardDataArr[i - sameCount + 1];
                    doubleLineCount += 2;

                    //结尾判断
                    if (i === (leftCardCount + firstCard - 2))
                        if ((this.gameLogic.getCardLogicValue(lastCard) - this.gameLogic.getCardLogicValue(tmpCardDataArr[i])) === 1 && (this.gameLogic.getCardLogicValue(tmpCardDataArr[i]) === this.gameLogic.getCardLogicValue(tmpCardDataArr[i + 1]))) {
                            doubleLineCard[doubleLineCount] = tmpCardDataArr[i];
                            doubleLineCard[doubleLineCount + 1] = tmpCardDataArr[i + 1];
                            doubleLineCount += 2;
                            break;
                        }

                }
                lastCard = tmpCardDataArr[i];
                sameCount = 1;
            }

            //保存数据
            if (doubleLineCount >= 4) {
                let index;

                //所有连牌
                let currentDoubleLineCount = 4;
                let currentDoubleLineIndex = 0;
                while (currentDoubleLineCount <= doubleLineCount) {
                    if (!!turnCardData && turnCardData.length > 0) {
                        if (currentDoubleLineCount !== turnCardData.length) {
                            currentDoubleLineIndex += 2;
                            if (currentDoubleLineIndex + currentDoubleLineCount > doubleLineCount) {
                                currentDoubleLineIndex = 0;
                                currentDoubleLineCount += 2;
                            }
                            continue;
                        }
                        if (this.gameLogic.getCardLogicValue(doubleLineCard[currentDoubleLineIndex]) <= turnFirstCardLogicValue) {
                            currentDoubleLineIndex = 0;
                            currentDoubleLineCount += 2;
                            continue;
                        }
                    }

                    index = cardTypeResult.cardTypeCount;
                    if (!cardTypeResult.cardDataArr[index]) cardTypeResult.cardDataArr[index] = [];
                    cardTypeResult.cardType = gameProto.cardType.DOUBLE_LINE;
                    cardTypeResult.cardDataArr[index] = doubleLineCard.slice(currentDoubleLineIndex, currentDoubleLineIndex + currentDoubleLineCount);
                    cardTypeResult.eachHandCardCount[index] = currentDoubleLineCount;
                    cardTypeResult.cardTypeCount++;

                    currentDoubleLineIndex += 2;
                    if (currentDoubleLineIndex + currentDoubleLineCount > doubleLineCount) {
                        currentDoubleLineIndex = 0;
                        currentDoubleLineCount += 2;
                    }
                }

                this.removeCard(doubleLineCard, tmpCardDataArr);
                isFindDoubleLine = true;
                leftCardCount -= doubleLineCount;
            }
        }
        return cardTypeResult;
    };

    // 获取三连类型
    getAllThreeLineCardType(handCardDataArr, turnCardData) {
        let cardTypeResult = {
            cardType: gameProto.cardType.THREE_LINE,
            cardTypeCount: 0,
            cardDataArr: [],
            eachHandCardCount: [],
        };
        let turnFirstCardLogicValue = !turnCardData ? 0 : this.gameLogic.getCardLogicValue(turnCardData[0]);
        //恢复扑克，防止分析时改变扑克
        let tmpCardDataArr = this.sortCardList(handCardDataArr.slice());
        let handCardCount = tmpCardDataArr.length;
        //连牌判断
        let firstCard = 0;
        //去除2和王
        for (let i = 0; i < handCardCount; ++i)
            if (this.gameLogic.getCardLogicValue(tmpCardDataArr[i]) < 15) {
                firstCard = i;
                break;
            }

        let leftCardCount = handCardCount - firstCard;
        let isFindThreeLine = true;
        let threeLineCount = 0;
        let threeLineCardArr = [];
        //开始判断
        while (leftCardCount >= 3 && isFindThreeLine) {
            let lastCard = tmpCardDataArr[firstCard];
            let sameCount = 1;
            threeLineCount = 0;
            isFindThreeLine = false;
            for (let i = firstCard + 1; i < leftCardCount + firstCard; ++i) {
                //搜索同牌
                while (this.gameLogic.getCardLogicValue(lastCard) === this.gameLogic.getCardLogicValue(tmpCardDataArr[i]) && i < leftCardCount + firstCard) {
                    ++sameCount;
                    ++i;
                }

                let lastThreeCardValue;
                if (threeLineCount > 0) lastThreeCardValue = this.gameLogic.getCardLogicValue(threeLineCardArr[threeLineCount - 1]);

                //重新开始
                if ((sameCount < 3 || (threeLineCount > 0 && (lastThreeCardValue - this.gameLogic.getCardLogicValue(lastCard)) !== 1)) && i <= leftCardCount + firstCard) {
                    if (threeLineCount >= 3) break;
                    if (sameCount >= 3) i -= sameCount;
                    lastCard = tmpCardDataArr[i];
                    threeLineCount = 0;
                }
                //保存数据
                else if (sameCount >= 3) {
                    threeLineCardArr[threeLineCount] = tmpCardDataArr[i - sameCount];
                    threeLineCardArr[threeLineCount + 1] = tmpCardDataArr[i - sameCount + 1];
                    threeLineCardArr[threeLineCount + 2] = tmpCardDataArr[i - sameCount + 2];
                    threeLineCount += 3;

                    //结尾判断
                    if (i === (leftCardCount + firstCard - 3))
                        if ((this.gameLogic.getCardLogicValue(lastCard) - this.gameLogic.getCardLogicValue(tmpCardDataArr[i])) === 1 && (this.gameLogic.getCardLogicValue(tmpCardDataArr[i]) === this.gameLogic.getCardLogicValue(tmpCardDataArr[i + 1])) && (this.gameLogic.getCardLogicValue(tmpCardDataArr[i]) === this.gameLogic.getCardLogicValue(tmpCardDataArr[i + 2]))) {
                            threeLineCardArr[threeLineCount] = tmpCardDataArr[i];
                            threeLineCardArr[threeLineCount + 1] = tmpCardDataArr[i + 1];
                            threeLineCardArr[threeLineCount + 2] = tmpCardDataArr[i + 2];
                            threeLineCount += 3;
                            break;
                        }

                }
                lastCard = tmpCardDataArr[i];
                sameCount = 1;
            }

            //保存数据
            if (threeLineCount >= 3) {
                let index;

                //所有连牌
                let currentCount = 3;
                let currentIndex = 0;
                while (currentCount <= threeLineCount) {
                    if (!!turnCardData && turnCardData.length > 0) {
                        if (currentCount !== turnCardData.length) {
                            currentIndex += 3;
                            if (currentIndex + currentCount > threeLineCount) {
                                currentIndex = 0;
                                currentCount += 3;
                            }
                            continue;
                        }
                        if (this.gameLogic.getCardLogicValue(threeLineCardArr[currentIndex]) <= turnFirstCardLogicValue) {
                            currentIndex = 0;
                            currentCount += 3;
                            continue;
                        }
                    }

                    index = cardTypeResult.cardTypeCount;
                    if (!cardTypeResult.cardDataArr[index]) cardTypeResult.cardDataArr[index] = [];
                    cardTypeResult.cardType = gameProto.cardType.THREE_LINE;
                    cardTypeResult.cardDataArr[index] = threeLineCardArr.slice(currentIndex, currentIndex + currentCount);
                    cardTypeResult.eachHandCardCount[index] = currentCount;
                    cardTypeResult.cardTypeCount++;

                    currentIndex += 3;
                    if (currentIndex + currentCount > threeLineCount) {
                        currentIndex = 0;
                        currentCount += 3;
                    }
                }

                this.removeCard(threeLineCardArr, tmpCardDataArr);
                isFindThreeLine = true;
                leftCardCount -= threeLineCount;
            }
        }
        return cardTypeResult;
    };

    // 获取三带1类型
    getAllThreeLineTakeOneCardType(handCardDataArr, turnCardData) {
        let cardTypeResult = {
            cardType: gameProto.cardType.THREE_LINE_TAKE_ONE,
            cardTypeCount: 0,
            cardDataArr: [],
            eachHandCardCount: [],
        };

        let turnFirstCardLogicValue = 0;
        let turnCardThree;
        if (!!turnCardData) {
            turnCardThree = this.getAllThreeCard(turnCardData);
            turnFirstCardLogicValue = this.gameLogic.getCardLogicValue(turnCardThree[0]);
        }

        //恢复扑克，防止分析时改变扑克
        let tmpCardDataArr = this.sortCardList(handCardDataArr.slice());

        //移除炸弹
        let allBomCardDataArr = this.getAllBombCard(tmpCardDataArr);
        this.removeCard(allBomCardDataArr, tmpCardDataArr);

        let handThreeCardArr = this.getAllThreeCard(tmpCardDataArr);
        let handThreeCount = handThreeCardArr.length;
        if (!turnCardData || (turnCardData.length === 4)) {
            let index;
            //去掉三条
            let remainCardDataArr = tmpCardDataArr.slice();
            this.removeCard(handThreeCardArr, remainCardDataArr);
            let remainCardCount = remainCardDataArr.length;
            //三条带一张
            for (let i = 0; i < handThreeCount; i += 3) {
                if (!!turnCardData && (this.gameLogic.getCardLogicValue(handThreeCardArr[i]) <= turnFirstCardLogicValue)) continue;
                //三条带一张
                for (let j = 0; j < remainCardCount; ++j) {
                    index = cardTypeResult.cardTypeCount;
                    if (!cardTypeResult.cardDataArr[index]) cardTypeResult.cardDataArr[index] = [];
                    cardTypeResult.cardType = gameProto.cardType.THREE_LINE_TAKE_ONE;
                    cardTypeResult.cardDataArr[index][0] = handThreeCardArr[i];
                    cardTypeResult.cardDataArr[index][1] = handThreeCardArr[i + 1];
                    cardTypeResult.cardDataArr[index][2] = handThreeCardArr[i + 2];
                    cardTypeResult.cardDataArr[index][3] = remainCardDataArr[j];
                    cardTypeResult.eachHandCardCount[index] = 4;
                    cardTypeResult.cardTypeCount++;
                }
            }
        }

        //三连带单
        let leftThreeCardCount = handThreeCount;
        let isFindThreeLine = true;
        let lastIndex = 0;
        if (this.gameLogic.getCardLogicValue(handThreeCardArr[0]) === 15) lastIndex = 3;
        while (leftThreeCardCount + lastIndex >= 6 && isFindThreeLine) {
            let lastLogicCard = this.gameLogic.getCardLogicValue(handThreeCardArr[lastIndex]);
            let threeLineCard = [];
            let threeLineCardCount = 3;
            threeLineCard[0] = handThreeCardArr[lastIndex];
            threeLineCard[1] = handThreeCardArr[lastIndex + 1];
            threeLineCard[2] = handThreeCardArr[lastIndex + 2];

            isFindThreeLine = false;
            for (let j = 3 + lastIndex; j < leftThreeCardCount; j += 3) {
                //连续判断
                if (1 !== (lastLogicCard - (this.gameLogic.getCardLogicValue(handThreeCardArr[j])))) {
                    lastIndex = j;
                    if (leftThreeCardCount - j >= 6) isFindThreeLine = true;
                    break;
                }
                lastLogicCard = this.gameLogic.getCardLogicValue(handThreeCardArr[j]);
                threeLineCard[threeLineCardCount] = handThreeCardArr[j];
                threeLineCard[threeLineCardCount + 1] = handThreeCardArr[j + 1];
                threeLineCard[threeLineCardCount + 2] = handThreeCardArr[j + 2];
                threeLineCardCount += 3;
            }
            if (threeLineCardCount > 3) {
                //移除三条（还应该移除炸弹王等）
                let remainCard = tmpCardDataArr.slice();
                this.removeCard(handThreeCardArr, remainCard);
                let remainCardCount = remainCard.length;

                for (let start = 0; start < threeLineCardCount - 3; start += 3) {
                    //本顺数目
                    let thisTreeLineCardCount = threeLineCardCount - start;
                    if (!!turnCardThree && (thisTreeLineCardCount !== turnCardThree.length || this.gameLogic.getCardLogicValue(threeLineCard[0]) <= turnFirstCardLogicValue)) {
                        continue;
                    }
                    //单牌个数
                    let singleCardCount = (thisTreeLineCardCount) / 3;
                    //单牌不够
                    if (remainCardCount < singleCardCount) continue;

                    //let flagArrs = utils.getCombinationFlagArrs(remainCardCount, singleCardCount);
                    let flagArrs = this.getCombinationFlagArrs(remainCardCount, singleCardCount);
                    for (let k = 0; k < flagArrs.length; ++k) {
                        let index = cardTypeResult.cardTypeCount;
                        if (!cardTypeResult.cardDataArr[index]) cardTypeResult.cardDataArr[index] = [];
                        cardTypeResult.cardType = gameProto.cardType.THREE_LINE_TAKE_ONE;
                        //保存三条
                        cardTypeResult.cardDataArr[index] = threeLineCard.slice(start, threeLineCardCount);
                        let flagArr = flagArrs[k];
                        for (let h = 0; h < flagArr.length; h++) {
                            //if (!!flagArr[h]){
                            cardTypeResult.cardDataArr[index].push(remainCard[flagArr[h]]);
                            //}
                        }
                        cardTypeResult.eachHandCardCount[index] = cardTypeResult.cardDataArr[index].length;
                        cardTypeResult.cardTypeCount++;
                    }
                }

                //移除三连
                isFindThreeLine = true;
                this.removeCard(threeLineCard, handThreeCardArr);
                leftThreeCardCount -= threeLineCardCount;
            }
        }
        return cardTypeResult;
    };

    // 获取三带2类型
    getAllThreeLineTakeTwoCardType(handCardDataArr, turnCardData) {
        let cardTypeResult = {
            cardType: gameProto.cardType.THREE_LINE_TAKE_TWO,
            cardTypeCount: 0,
            cardDataArr: [],
            eachHandCardCount: [],
        };

        let turnFirstCardLogicValue = 0;
        let turnCardThree;
        if (!!turnCardData) {
            turnCardThree = this.getAllThreeCard(turnCardData);
            turnFirstCardLogicValue = this.gameLogic.getCardLogicValue(turnCardThree[0]);
        }

        //恢复扑克，防止分析时改变扑克
        let tmpCardDataArr = this.sortCardList(handCardDataArr.slice());

        //移除炸弹
        let allBomCardDataArr = this.getAllBombCard(tmpCardDataArr);
        this.removeCard(allBomCardDataArr, tmpCardDataArr);

        let handThreeCardArr = this.getAllThreeCard(tmpCardDataArr);
        let handThreeCount = handThreeCardArr.length;
        if (!turnCardData || (turnCardData.length === 5)) {
            //去掉三条
            let remainCardDataArr = tmpCardDataArr.slice();
            this.removeCard(handThreeCardArr, remainCardDataArr);
            let remainCardCount = remainCardDataArr.length;
            //三条带2张
            for (let i = 0; i < handThreeCount; i += 3) {
                if (!!turnCardData && (this.gameLogic.getCardLogicValue(handThreeCardArr[i]) <= turnFirstCardLogicValue)) continue;
                //let flagArrs = utils.getCombinationFlagArrs(remainCardCount, 2);
                let flagArrs = this.getCombinationFlagArrs(remainCardCount, 2);
                for (let j = 0; j < flagArrs.length; ++j) {
                    let index = cardTypeResult.cardTypeCount;
                    if (!cardTypeResult.cardDataArr[index]) cardTypeResult.cardDataArr[index] = [];
                    cardTypeResult.cardType = gameProto.cardType.THREE_LINE_TAKE_TWO;
                    cardTypeResult.cardDataArr[index][0] = handThreeCardArr[i];
                    cardTypeResult.cardDataArr[index][1] = handThreeCardArr[i + 1];
                    cardTypeResult.cardDataArr[index][2] = handThreeCardArr[i + 2];
                    let flagArr = flagArrs[j];
                    for (let k = 0; k < flagArr.length; ++k) {
                        // if (flagArr[k]){
                        cardTypeResult.cardDataArr[index].push(remainCardDataArr[flagArr[k]]);
                        // }
                    }
                    cardTypeResult.eachHandCardCount[index] = 5;
                    cardTypeResult.cardTypeCount++;
                }
            }
            //特殊重组
            if (remainCardCount <= 1) {
                remainCardDataArr = tmpCardDataArr.slice();
                let remainCardCount = remainCardDataArr.length;
                for (let i = 0; i < handThreeCount; i += 3) {
                    if (!!turnCardData && (this.gameLogic.getCardLogicValue(handThreeCardArr[i]) <= turnFirstCardLogicValue)) continue;
                    //let flagArrs = utils.getCombinationFlagArrs(remainCardCount, 2);
                    let flagArrs = this.getCombinationFlagArrs(remainCardCount, 2);
                    for (let j = 0; j < flagArrs.length; ++j) {
                        let isSAN = false;
                        let flagArr = flagArrs[j];
                        for (let k = 0; k < flagArr.length; ++k) {
                            if (remainCardDataArr[flagArr[k]] == handThreeCardArr[i] || remainCardDataArr[flagArr[k]] == handThreeCardArr[i + 1] ||
                                remainCardDataArr[flagArr[k]] == handThreeCardArr[i + 2]
                            ) {
                                isSAN = true;
                                break;
                            }
                        }
                        if (isSAN) {
                            continue;
                        }
                        let index = cardTypeResult.cardTypeCount;
                        if (!cardTypeResult.cardDataArr[index]) cardTypeResult.cardDataArr[index] = [];
                        cardTypeResult.cardType = gameProto.cardType.THREE_LINE_TAKE_TWO;
                        cardTypeResult.cardDataArr[index][0] = handThreeCardArr[i];
                        cardTypeResult.cardDataArr[index][1] = handThreeCardArr[i + 1];
                        cardTypeResult.cardDataArr[index][2] = handThreeCardArr[i + 2];
                        for (let k = 0; k < flagArr.length; ++k) {
                            cardTypeResult.cardDataArr[index].push(remainCardDataArr[flagArr[k]]);
                        }
                        cardTypeResult.eachHandCardCount[index] = 5;
                        cardTypeResult.cardTypeCount++;
                    }
                }
            }
        }

        //三连带2
        let leftThreeCardCount = handThreeCount;
        let isFindThreeLine = true;
        let lastIndex = 0;
        if (this.gameLogic.getCardLogicValue(handThreeCardArr[0]) === 15) lastIndex = 3;
        while (leftThreeCardCount + lastIndex >= 6 && isFindThreeLine) {
            let lastLogicCard = this.gameLogic.getCardLogicValue(handThreeCardArr[lastIndex]);
            let threeLineCard = [];
            let threeLineCardCount = 3;
            threeLineCard[0] = handThreeCardArr[lastIndex];
            threeLineCard[1] = handThreeCardArr[lastIndex + 1];
            threeLineCard[2] = handThreeCardArr[lastIndex + 2];

            isFindThreeLine = false;
            for (let j = 3 + lastIndex; j < leftThreeCardCount; j += 3) {
                //连续判断
                if (1 !== (lastLogicCard - (this.gameLogic.getCardLogicValue(handThreeCardArr[j])))) {
                    lastIndex = j;
                    if (leftThreeCardCount - j >= 6) isFindThreeLine = true;
                    break;
                }
                lastLogicCard = this.gameLogic.getCardLogicValue(handThreeCardArr[j]);
                threeLineCard[threeLineCardCount] = handThreeCardArr[j];
                threeLineCard[threeLineCardCount + 1] = handThreeCardArr[j + 1];
                threeLineCard[threeLineCardCount + 2] = handThreeCardArr[j + 2];
                threeLineCardCount += 3;
            }
            if (threeLineCardCount > 3) {
                //移除三条（还应该移除炸弹王等）
                let remainCard = tmpCardDataArr.slice();
                this.removeCard(handThreeCardArr, remainCard);
                let remainCardCount = remainCard.length;

                for (let start = 0; start < threeLineCardCount - 3; start += 3) {
                    //本顺数目
                    let thisTreeLineCardCount = threeLineCardCount - start;
                    if (!!turnCardThree && (thisTreeLineCardCount !== turnCardThree.length || this.gameLogic.getCardLogicValue(threeLineCard[0]) <= turnFirstCardLogicValue)) {
                        continue;
                    }
                    //单牌个数
                    let singleCardCount = (thisTreeLineCardCount) / 3 * 2;
                    //单牌不够
                    if (remainCardCount < singleCardCount) continue;

                    //let flagArrs = utils.getCombinationFlagArrs(remainCardCount, singleCardCount);
                    let flagArrs = this.getCombinationFlagArrs(remainCardCount, singleCardCount);
                    for (let k = 0; k < flagArrs.length; ++k) {
                        let index = cardTypeResult.cardTypeCount;
                        if (!cardTypeResult.cardDataArr[index]) cardTypeResult.cardDataArr[index] = [];
                        cardTypeResult.cardType = gameProto.cardType.THREE_LINE_TAKE_TWO;
                        //保存三条
                        cardTypeResult.cardDataArr[index] = threeLineCard.slice(start, threeLineCardCount);
                        let flagArr = flagArrs[k];
                        for (let h = 0; h < flagArr.length; h++) {
                            //if (!!flagArr[h]){
                            cardTypeResult.cardDataArr[index].push(remainCard[flagArr[h]]);
                            //}
                        }
                        cardTypeResult.eachHandCardCount[index] = cardTypeResult.cardDataArr[index].length;
                        cardTypeResult.cardTypeCount++;
                    }
                }

                //移除三连
                isFindThreeLine = true;
                this.removeCard(threeLineCard, handThreeCardArr);
                leftThreeCardCount -= threeLineCardCount;
            }
        }
        return cardTypeResult;
    };

    getCombinationFlagArrs(remainCardDataArr, turnCardData) {
        let flagArrs = [];
        if (turnCardData == 1) {
            for (let i = 0; i < remainCardDataArr; i++) {
                flagArrs.push([i]);
            }
        } else if (turnCardData == 2) {
            for (let i = 0; i < remainCardDataArr; i++) {
                for (let j = i + 1; j < remainCardDataArr; j++) {
                    flagArrs.push([i, j]);
                }
            }
        } else if (turnCardData == 3) {
            for (let i = 0; i < remainCardDataArr; i++) {
                for (let j = i + 1; j < remainCardDataArr; j++) {
                    for (let k = j + 1; k < remainCardDataArr; k++) {
                        flagArrs.push([i, j, k]);
                    }
                }
            }
        } else if (turnCardData == 4) {
            for (let i = 0; i < remainCardDataArr; i++) {
                for (let j = i + 1; j < remainCardDataArr; j++) {
                    for (let k = j + 1; k < remainCardDataArr; k++) {
                        for (let c = k + 1; c < remainCardDataArr; c++) {
                            flagArrs.push([i, j, k, c]);
                        }
                    }
                }
            }
        }
        return flagArrs;
    }
    // 获取四带单类型
    getAllFourLineTakeXCardType(handCardDataArr, turnCardData) {
        let cardTypeResult = {
            cardType: gameProto.cardType.FOUR_LINE_TAKE_X,
            cardTypeCount: 0,
            cardDataArr: [],
            eachHandCardCount: [],
        };
        if (handCardDataArr.length < 5) return cardTypeResult;
        //恢复扑克，防止分析时改变扑克
        let tmpCardDataArr = handCardDataArr.slice();
        let handCardCount = tmpCardDataArr.length;

        let handAllFourCardData = this.getAllBombCard(tmpCardDataArr.slice());
        let handAllFourCardCount = handCardDataArr.length;

        if (handAllFourCardCount <= 0) return cardTypeResult;

        let turnAllFourCardData = [];
        let turnFirstCardLogicValue = 0;
        if (!!turnCardData) {
            turnAllFourCardData = this.getAllBombCard(turnCardData);
            turnFirstCardLogicValue = this.gameLogic.getCardLogicValue(turnAllFourCardData[0]);
        }

        if (!!turnCardData && this.gameLogic.getCardLogicValue(handAllFourCardData[0]) <= turnFirstCardLogicValue) return cardTypeResult;


        let canOutFourCardData = [];
        let canOutFourCardCount = 0;
        if (!!turnCardData) {
            //可出的牌
            for (let i = 0; i < handAllFourCardCount; i += 4) {
                if (this.gameLogic.getCardLogicValue(handAllFourCardData[i]) > turnFirstCardLogicValue) {
                    canOutFourCardData[canOutFourCardCount] = handAllFourCardData[i];
                    canOutFourCardData[canOutFourCardCount + 1] = handAllFourCardData[i + 1];
                    canOutFourCardData[canOutFourCardCount + 2] = handAllFourCardData[i + 2];
                    canOutFourCardData[canOutFourCardCount + 3] = handAllFourCardData[i + 3];
                    canOutFourCardCount += 4;
                }
            }
            if ((handCardCount - canOutFourCardCount) < (turnCardData.length - turnAllFourCardData.length)) return cardTypeResult;
        } else {
            canOutFourCardData = handAllFourCardData;
            canOutFourCardCount = handCardDataArr.length;
        }

        let remainCard = tmpCardDataArr.slice();
        this.removeCard(canOutFourCardData, remainCard);
        for (let start = 0; start < canOutFourCardCount; start += 4) {
            for (let i = 1; i <= 4; ++i) {
                // let flagArrs = utils.getCombinationFlagArrs(remainCard.length, i);
                let flagArrs = this.getCombinationFlagArrs(remainCard.length, i);
                for (let j = 0; j < flagArrs.length; ++j) {
                    let flagArr = flagArrs[j];
                    let index = cardTypeResult.cardTypeCount;
                    cardTypeResult.cardDataArr[index] = canOutFourCardData.slice(start, start + 4);
                    for (let k = 0; k < flagArr.length; ++k) {
                        //if (!!flagArr[k]){
                        cardTypeResult.cardDataArr[index].push(remainCard[flagArr[k]]);
                        //}
                    }
                    cardTypeResult.eachHandCardCount[index] = cardTypeResult.cardDataArr[index].length;
                    cardTypeResult.cardTypeCount++;
                }
            }
        }
        return cardTypeResult;
    };

    // 获取炸弹类型
    getAllBombCardType(handCardDataArr, turnCardData) {
        let cardTypeResult = {
            cardType: gameProto.cardType.BOMB_CARD,
            cardTypeCount: 0,
            cardDataArr: [],
            eachHandCardCount: [],
        };
        let fourCardData = this.getAllBombCard(handCardDataArr);
        for (let i = 0; i < fourCardData.length; i += 4) {
            if (!!turnCardData && turnCardData.length > 0) {
                if (this.gameLogic.getCardLogicValue(fourCardData[i]) <= this.gameLogic.getCardLogicValue(turnCardData[0])) continue;
            }
            let index = cardTypeResult.cardTypeCount;
            if (!cardTypeResult.cardDataArr[index]) cardTypeResult.cardDataArr[index] = [];
            cardTypeResult.cardType = gameProto.cardType.BOMB_CARD;
            cardTypeResult.cardDataArr[index][0] = fourCardData[i];
            cardTypeResult.cardDataArr[index][1] = fourCardData[i + 1];
            cardTypeResult.cardDataArr[index][2] = fourCardData[i + 2];
            cardTypeResult.cardDataArr[index][3] = fourCardData[i + 3];
            cardTypeResult.eachHandCardCount[index] = 4;
            cardTypeResult.cardTypeCount++;
        }
        return cardTypeResult;
    };
    //获取3A天炸
    getAllTianBombCardType(handCardDataArr, turnCardData) {
        let cardTypeResult = {
            cardType: gameProto.cardType.TIAN_BOMB,
            cardTypeCount: 0,
            cardDataArr: [],
            eachHandCardCount: [],
        };
        //大小排序
        let {
            countList
        } = this.gameLogic.getCardsAndCount(handCardDataArr);

        //是否3A炸弹
        for (let index = 0; index < countList.length; index++) {
            let lincountList = [];
            lincountList[0] = countList[index];
            if (this.gameRule.a3Boom && this.gameLogic.isTianZha(lincountList)) {
                cardTypeResult.cardType = gameProto.cardType.TIAN_BOMB;
                cardTypeResult.cardDataArr[0] = [];
                cardTypeResult.cardDataArr[0][0] = 1;
                cardTypeResult.cardDataArr[0][1] = 17;
                cardTypeResult.cardDataArr[0][2] = 33;
                cardTypeResult.eachHandCardCount[0] = 3;
                cardTypeResult.cardTypeCount++;

            }
        }
        return cardTypeResult;
    }
    analyseOutCardTypeActive(handCardDataArr) {
        let cardTypeResultArr = [];
        // 初始化结果
        for (let i = 0; i <= 12; ++i) {
            cardTypeResultArr.push({
                cardTypeCount: 0,
                cardDataArr: [],
                eachHandCardCount: [],
                cardType: i
            })
        }
        let linhandCardDataArr = handCardDataArr.slice();
        let cardCount = {};
        for (let i = 0; i < linhandCardDataArr.length; i++) {
            let cardValue = this.gameLogic.getCardLogicValue(linhandCardDataArr[i]);
            if (!cardCount[cardValue]) {
                cardCount[cardValue] = [];
            }
            cardCount[cardValue].push(linhandCardDataArr[i]);
        }
        if (!this.gameRule.chaizhadan) {
            for (let key in cardCount) {
                if (cardCount[key].length >= 4) {
                    for (let index = 0; index < cardCount[key].length; index++) {
                        linhandCardDataArr.splice(linhandCardDataArr.indexOf(cardCount[key][index]), 1);
                    }
                }
            }
        }
        cardTypeResultArr[gameProto.cardType.SINGLE] = this.getAllSingleCardType(linhandCardDataArr);

        cardTypeResultArr[gameProto.cardType.DOUBLE] = this.getAllDoubleCardType(linhandCardDataArr);

        cardTypeResultArr[gameProto.cardType.SINGLE_LINE] = this.getAllLineCardType(linhandCardDataArr);

        cardTypeResultArr[gameProto.cardType.DOUBLE_LINE] = this.getAllDoubleLineCardType(linhandCardDataArr);

        //if (handCardDataArr.length == 3 && this.gameRule.baiwei) {
        cardTypeResultArr[gameProto.cardType.THREE_LINE] = this.getAllThreeLineCardType(linhandCardDataArr);
        //}
        //if (handCardDataArr.length == 4 && this.gameRule.baiwei) {
        cardTypeResultArr[gameProto.cardType.THREE_LINE_TAKE_ONE] = this.getAllThreeLineTakeOneCardType(linhandCardDataArr);
        //}
        cardTypeResultArr[gameProto.cardType.THREE_LINE_TAKE_TWO] = this.getAllThreeLineTakeTwoCardType(linhandCardDataArr);

        cardTypeResultArr[gameProto.cardType.BOMB_CARD] = this.getAllBombCardType(handCardDataArr);

        cardTypeResultArr[gameProto.cardType.TIAN_BOMB] = this.getAllTianBombCardType(handCardDataArr);

        return cardTypeResultArr;
    };

    analyseOutCardTypePassive(handCardDataArr, turnCardData, cardTypeResultArr) {
        // 初始化结果
        for (let i = 0; i <= 12; ++i) {
            cardTypeResultArr.push({
                cardTypeCount: 0,
                cardDataArr: [],
                eachHandCardCount: [],
                cardType: i
            })
        }

        let tmpCardDataArr = this.sortCardList(handCardDataArr.slice());
        let turnCardType = this.gameLogic.getCardType(turnCardData, this.gameRule);
        if (turnCardType === gameProto.cardType.ERROR) {
            console.error("turnCardType err");
            return;
        }
        if (turnCardType !== gameProto.cardType.BOMB_CARD && turnCardType !== gameProto.cardType.TIAN_BOMB) {
            cardTypeResultArr[gameProto.cardType.BOMB_CARD] = this.getAllBombCardType(tmpCardDataArr);
            cardTypeResultArr[gameProto.cardType.TIAN_BOMB] = this.getAllTianBombCardType(tmpCardDataArr);
        }

        let linhandCardDataArr = handCardDataArr.slice();
        let cardCount = {};
        for (let i = 0; i < linhandCardDataArr.length; i++) {
            let cardValue = this.gameLogic.getCardLogicValue(linhandCardDataArr[i]);
            if (!cardCount[cardValue]) {
                cardCount[cardValue] = [];
            }
            cardCount[cardValue].push(linhandCardDataArr[i]);
        }
        if (!this.gameRule.chaizhadan) {
            for (let key in cardCount) {
                if (cardCount[key].length >= 4) {
                    for (let index = 0; index < cardCount[key].length; index++) {
                        linhandCardDataArr.splice(linhandCardDataArr.indexOf(cardCount[key][index]), 1);
                    }
                }
            }
        }
        switch (turnCardType) {
            case gameProto.cardType.SINGLE: //单牌类型
            {
                cardTypeResultArr[gameProto.cardType.SINGLE] = this.getAllSingleCardType(linhandCardDataArr, turnCardData);
                break;
            }
            case gameProto.cardType.DOUBLE: //对牌类型
            {
                cardTypeResultArr[gameProto.cardType.DOUBLE] = this.getAllDoubleCardType(linhandCardDataArr, turnCardData);
                break;
            }
            case gameProto.cardType.SINGLE_LINE: //单连类型
            {
                cardTypeResultArr[gameProto.cardType.SINGLE_LINE] = this.getAllLineCardType(linhandCardDataArr, turnCardData);
                break;
            }
            case gameProto.cardType.DOUBLE_LINE: //对连类型
            {
                cardTypeResultArr[gameProto.cardType.DOUBLE_LINE] = this.getAllDoubleLineCardType(linhandCardDataArr, turnCardData);
                break;
            }
            case gameProto.cardType.THREE_LINE: //三连类型
            {
                //if (handCardDataArr.length == 3 && this.gameRule.baiwei) {
                cardTypeResultArr[gameProto.cardType.THREE_LINE] = this.getAllThreeLineCardType(linhandCardDataArr, turnCardData);
                break;
                //}

            }
            case gameProto.cardType.THREE_LINE_TAKE_ONE: //三带一单
            {
                //if (handCardDataArr.length == 4 && this.gameRule.baiwei) {
                cardTypeResultArr[gameProto.cardType.THREE_LINE_TAKE_ONE] = this.getAllThreeLineTakeOneCardType(linhandCardDataArr, turnCardData);
                break;
                //}
            }
            case gameProto.cardType.THREE_LINE_TAKE_TWO: //三带一对
            {
                cardTypeResultArr[gameProto.cardType.THREE_LINE_TAKE_TWO] = this.getAllThreeLineTakeTwoCardType(linhandCardDataArr, turnCardData);
                break;
            }
            //case gameProto.cardType.FOUR_LINE_TAKE_X: //四带两单
            //{
            //cardTypeResultArr[gameProto.cardType.FOUR_LINE_TAKE_X] = this.getAllFourLineTakeXCardType(handCardDataArr, turnCardData);
            //break;
            //}
            case gameProto.cardType.BOMB_CARD: //炸弹类型
            {
                cardTypeResultArr[gameProto.cardType.BOMB_CARD] = this.getAllBombCardType(handCardDataArr, turnCardData);
                cardTypeResultArr[gameProto.cardType.TIAN_BOMB] = this.getAllTianBombCardType(handCardDataArr);
                break;
            }
            default:
                break;
        }

    };

    /********************************************************************
     函数名：Combination
     参数：
     cbCombineCardData：存储单个的组合结果
     cbResComLen：已得到的组合长度，开始调用时此参数为0
     cbResultCardData：存储所有的组合结果
     cbResCardLen：cbResultCardData的第一下标的长度，组合结果的个数
     cbSrcCardData：需要做组合的数据
     cbSrcLen：cbSrcCardData的数据数目
     cbCombineLen2，cbCombineLen1：组合的长度，开始调用时两者相等。
     *********************************************************************/
    //组合算法
    combination(combineCardDataArr, resComLen, resultCardData, srcCardData, combineLen1, combineLen2) {
        if (resComLen === combineLen2) {
            resultCardData.push(combineCardDataArr.slice(0, resComLen));
        } else {
            if (combineLen1 >= 1 && srcCardData.length > 0) {
                combineCardDataArr[combineLen2 - combineLen1] = srcCardData[0];
                ++resComLen;
                this.combination(combineCardDataArr, resComLen, resultCardData, srcCardData.slice(1, srcCardData.length), combineLen1 - 1, combineLen2);

                --resComLen;
                this.combination(combineCardDataArr, resComLen, resultCardData, srcCardData.slice(1, srcCardData.length), combineLen1, combineLen2);
            }
        }
    };

    //排列算法
    permutation(list, m, n, result) {
        let j, temp;
        if (m === n) {
            let arr = [];
            for (j = 0; j < n; j++) {
                arr[j] = list[j];
            }
            if (arr.length > 0) result.push(arr);
        } else {
            for (j = m; j < n; j++) {
                temp = list[m];
                list[m] = list[j];
                list[j] = temp;
                this.permutation(list, m + 1, n, result);
                temp = list[m];
                list[m] = list[j];
                list[j] = temp;
            }
        }
    };

    // 分析单排数量
    analyseSingleCardCount(handCardDataArr, wantOutCardDataArr, singleCardDataArr) {
        //参数判断
        if (handCardDataArr.length <= 0) return MAX_COUNT + 5;

        let remainCard = this.sortCardList(handCardDataArr.slice());

        let wantOutCardCount = 0;
        if (!!wantOutCardDataArr) wantOutCardCount = wantOutCardDataArr.length;
        //移除扑克
        if (wantOutCardCount !== 0) this.removeCard(wantOutCardDataArr, remainCard);

        let getAllCardFunArray = [];
        getAllCardFunArray[0] = this.getAllBombCard.bind(this);
        getAllCardFunArray[1] = this.getAllLineCard.bind(this);
        getAllCardFunArray[2] = this.getAllThreeCard.bind(this);
        getAllCardFunArray[3] = this.getAllDoubleCard.bind(this);

        //指针数组下标
        let indexArray = [0, 1, 2, 3];
        //排列结果
        let permutationRes = [];
        //计算排列
        this.permutation(indexArray, 0, 4, permutationRes);
        if (permutationRes.length !== 24) return MAX_COUNT + 5;

        //单牌数目
        let minSingleCardCount = MAX_COUNT + 5;
        //计算最小值
        for (let i = 0; i < 24; ++i) {
            //保留数据
            let tmpCardDataArr = remainCard.slice();

            for (let j = 0; j < 4; ++j) {
                let index = permutationRes[i][j];
                if (index < 0 || index >= 4) {
                    console.error("ai logic arr err: index<0 || index>=4");
                    return MAX_COUNT + 5;
                }
                let tmpGetAllCardFun = getAllCardFunArray[index];
                //提取扑克
                let getCardData = tmpGetAllCardFun(tmpCardDataArr);
                //删除扑克
                if (getCardData.length !== 0) this.removeCard(getCardData, tmpCardDataArr);
            }

            //计算单牌
            let singleCard = this.getAllSingleCard(tmpCardDataArr);
            if (minSingleCardCount > singleCard.length) {
                minSingleCardCount = singleCard.length;
                //保存单牌
                if (!!singleCardDataArr) {
                    singleCardDataArr.splice(0, singleCardDataArr.length);
                    for (let k = 0; k < singleCard.length; ++k) {
                        singleCardDataArr.push(singleCard[k])
                    }
                }
            }
        }

        let wantOutCardType = this.gameLogic.getCardType(wantOutCardDataArr, this.gameRule);
        //带大牌判断 && this.gameRule.baiwei
        if (wantOutCardCount > 0) {
            //出牌类型
            if (wantOutCardType === gameProto.cardType.THREE_LINE_TAKE_ONE || wantOutCardType === gameProto.cardType.THREE_LINE_TAKE_TWO) {
                for (let i = 3; i < wantOutCardCount; ++i) {
                    if (this.gameLogic.getCardLogicValue(wantOutCardDataArr[i]) >= 14) minSingleCardCount += 3;
                }
            }
        }

        //三条类型判断 && this.gameRule.baiwei
        if (wantOutCardCount > 0) {
            // 出牌类型
            if (wantOutCardType === gameProto.cardType.THREE_LINE) {
                minSingleCardCount += (wantOutCardCount / 3);
            }
        }

        //拆三条判断
        if (wantOutCardType === gameProto.cardType.DOUBLE) {
            let allThreeCardData = this.getAllThreeCard(handCardDataArr);
            let allThreeCount = allThreeCardData.length;
            let allLineCardData = this.getAllLineCard(handCardDataArr);
            let allLineCount = allLineCardData.length;

            let threeCardValue = 0;
            for (let i = 0; i < allThreeCount; ++i) {
                for (let j = 0; j < wantOutCardCount; ++j) {
                    if (this.gameLogic.getCardLogicValue(wantOutCardDataArr[j]) === this.gameLogic.getCardLogicValue(allThreeCardData[i])) {
                        threeCardValue = this.gameLogic.getCardValue(wantOutCardDataArr[j]);
                        break;
                    }
                }
            }

            //是否有连牌
            let isInLineCard = false;
            for (let lineCardIndex = 0; lineCardIndex < allLineCount; ++lineCardIndex) {
                if (this.gameLogic.getCardValue(allLineCardData[lineCardIndex]) === threeCardValue) {
                    isInLineCard = true;
                    break;
                }
            }

            if (!isInLineCard && threeCardValue !== 0) minSingleCardCount += 2;
        }

        //拆炸判断
        if (wantOutCardCount !== 0) {
            //炸弹扑克
            let bombCard = this.getAllBombCard(handCardDataArr);
            let bombCardCount = bombCard.length;

            //出牌类型
            let cardType = wantOutCardType;

            if (bombCardCount > 0 && cardType < gameProto.cardType.BOMB_CARD) {
                //寻找相同
                for (let i = (this.gameLogic.getCardColor(bombCard[0]) === 4 ? 2 : 0); i < bombCardCount; i += 4) {
                    for (let j = 0; j < wantOutCardCount; ++j) {
                        if (this.gameLogic.getCardValue(bombCard[i]) === this.gameLogic.getCardValue(wantOutCardDataArr[j]) && this.gameLogic.getCardLogicValue(wantOutCardDataArr[j]) < 15) {
                            if (cardType !== gameProto.cardType.SINGLE_LINE && cardType !== gameProto.cardType.DOUBLE_LINE) {
                                return MAX_COUNT + 5; // 不拆炸弹
                            } else {
                                minSingleCardCount += 2; // 不拆炸弹
                            }
                        }
                    }
                }

                //多个炸弹判断
                if (cardType === gameProto.cardType.SINGLE_LINE) {
                    let bombCount = 0;

                    for (let i = this.gameLogic.getCardColor(bombCard[0]) === 4 ? 2 : 0; i < bombCount; i += 4)
                        for (let j = 0; j < wantOutCardCount; ++j)
                            if (this.gameLogic.getCardValue(bombCard[i]) === this.gameLogic.getCardValue(wantOutCardDataArr[j])) ++bombCount;

                    if (bombCount >= 2) return MAX_COUNT; //不拆炸弹

                    //三条个数
                    let analyseResult = this.gameLogic.analyseCardDataArr(handCardDataArr);

                    let threeCount = 0;

                    for (let i = 0; i < analyseResult.threeCardData.length; ++i)
                        for (let j = 0; j < wantOutCardCount; ++j)
                            if (this.gameLogic.getCardValue(wantOutCardDataArr[j]) === this.gameLogic.getCardValue(analyseResult.threeCardData[3 * i])) ++threeCount;

                    if (threeCount + bombCount >= 2) return MAX_COUNT + 5;

                }
            }
        }
        return minSingleCardCount;
    };

    // 主动出牌
    outCardActive(handCardDataArr) {
        // handCardDataArr=[ 0x03,0x04,0x05,0x06,0x07,0x08,0x18];
        let outCardResult = {
            cardCount: 0,
            resultCard: []
        };

        let handCardCount = handCardDataArr.length;

        let cardType = this.gameLogic.getCardType(handCardDataArr.slice(), this.gameRule);
        //只剩一手牌
        if (cardType !== gameProto.cardType.ERROR) {
            outCardResult.cardCount = handCardCount;
            outCardResult.resultCard = handCardDataArr.slice();
            return outCardResult;
        }
        //判断可否出完
        let isFindOutCard = false;
        let cardTypeResultArr = this.analyseOutCardTypeActive(handCardDataArr);

        let minSingleCardCount = MAX_COUNT;
        for (let cardType = gameProto.cardType.SINGLE; cardType <= gameProto.cardType.BOMB_CARD; ++cardType) {
            let cardTypeResult = cardTypeResultArr[cardType];
            if (cardTypeResult.cardTypeCount > 0) {
                for (let index = 0; index < cardTypeResult.cardTypeCount; ++index) {
                    //计算单牌
                    let tmpSingleCount = this.analyseSingleCardCount(handCardDataArr, cardTypeResult.cardDataArr[index]);

                    //结果判断
                    if (tmpSingleCount >= MAX_COUNT) continue;

                    //炸弹优先级排后
                    let bombCardType = this.gameLogic.getCardType(cardTypeResult.cardDataArr[index], this.gameRule);
                    if (handCardCount <= 10) {
                        if (bombCardType === gameProto.cardType.BOMB_CARD) tmpSingleCount += 8;
                        else if (bombCardType === gameProto.cardType.FOUR_LINE_TAKE_X) tmpSingleCount += 9;
                        else if (bombCardType === gameProto.cardType.THREE_LINE_TAKE_TWO) tmpSingleCount += 1;
                        else if (bombCardType === gameProto.cardType.THREE_LINE) tmpSingleCount += 2;
                        else if (bombCardType === gameProto.cardType.DOUBLE_LINE) tmpSingleCount += 3;
                        else if (bombCardType === gameProto.cardType.SINGLE_LINE) tmpSingleCount += 4;
                        else if (bombCardType === gameProto.cardType.DOUBLE) tmpSingleCount += 5;
                        else if (bombCardType === gameProto.cardType.SINGLE) tmpSingleCount += 6;
                    } else {
                        if (bombCardType === gameProto.cardType.BOMB_CARD) tmpSingleCount += 8;
                        else if (bombCardType === gameProto.cardType.FOUR_LINE_TAKE_X) tmpSingleCount += 9;
                        else if (10 >= this.gameLogic.getCardLogicValue(cardTypeResult.cardDataArr[index][0])) tmpSingleCount += 2;
                        else if (10 < this.gameLogic.getCardLogicValue(cardTypeResult.cardDataArr[index][0])) tmpSingleCount += 7;
                    }
                    if (tmpSingleCount <= minSingleCardCount) {
                        //设置变量
                        outCardResult.cardCount = cardTypeResult.eachHandCardCount[index];
                        outCardResult.resultCard = cardTypeResult.cardDataArr[index].slice();
                        minSingleCardCount = tmpSingleCount;
                        isFindOutCard = true;
                    }
                }
            }
        }
        if (!isFindOutCard) {
            // 没有能出的牌，出最多的一手牌
            let maxCardCount = -1;
            for (let cardType = gameProto.cardType.SINGLE; cardType <= gameProto.cardType.BOMB_CARD; ++cardType) {
                let cardTypeResult = cardTypeResultArr[cardType];
                if (cardTypeResult.cardTypeCount > 0) {
                    for (let index = 0; index < cardTypeResult.cardTypeCount; ++index) {
                        if (cardTypeResult.cardDataArr[index].length > maxCardCount) {
                            outCardResult.cardCount = cardTypeResult.eachHandCardCount[index];
                            outCardResult.resultCard = cardTypeResult.cardDataArr[index].slice();
                            maxCardCount = outCardResult.resultCard.length;
                        }
                    }
                }
            }
        }
        return outCardResult;
    };

    // 被动出牌
    outCardPassive(handCardDataArr, turnCardDataArr, nextCardDataArr) {
        let outCardResult = {
            cardCount: 0,
            resultCard: []
        };

        let handCardCount = handCardDataArr.length;
        //出牌类型
        let outCardType = this.gameLogic.getCardType(turnCardDataArr, this.gameRule);

        let nextCardType = this.gameLogic.getCardType(nextCardDataArr, this.gameRule);

        let cardTypeResultArr = [];
        this.analyseOutCardTypePassive(handCardDataArr, turnCardDataArr, cardTypeResultArr);

        //只剩炸弹
        if (handCardCount === cardTypeResultArr[gameProto.cardType.BOMB_CARD].eachHandCardCount[0] && (outCardType < gameProto.cardType.BOMB_CARD ||
                this.gameLogic.getCardLogicValue(cardTypeResultArr[gameProto.cardType.BOMB_CARD].cardDataArr[0][0]) > this.gameLogic.getCardLogicValue(turnCardDataArr[0]))) {
            outCardResult.cardCount = cardTypeResultArr[gameProto.cardType.BOMB_CARD].eachHandCardCount[0];
            outCardResult.resultCard = cardTypeResultArr[gameProto.cardType.BOMB_CARD].cardDataArr[0].slice();
            return outCardResult;
        }

        //判断可否出完
        let minSingleCardCount = MAX_COUNT;
        for (let cardType = gameProto.cardType.SINGLE; cardType <= gameProto.cardType.BOMB_CARD; ++cardType)
            if (cardTypeResultArr[cardType].cardTypeCount > 0) {
                let cardTypeResult = cardTypeResultArr[cardType];
                for (let i = 0; i < cardTypeResult.cardTypeCount; ++i) {
                    //计算单牌
                    let tmpSingleCount = this.analyseSingleCardCount(handCardDataArr, cardTypeResult.cardDataArr[i]);
                    //结果判断
                    if (tmpSingleCount >= MAX_COUNT) continue;

                    //炸弹优先级排后
                    let bombCardType = this.gameLogic.getCardType(cardTypeResult.cardDataArr[i], cardTypeResult.eachHandCardCount[i], this.gameRule);
                    if (bombCardType === gameProto.cardType.BOMB_CARD) tmpSingleCount += 4;

                    if (tmpSingleCount <= minSingleCardCount) {
                        //设置变量
                        outCardResult.cardCount = cardTypeResult.eachHandCardCount[i];
                        outCardResult.resultCard = cardTypeResult.cardDataArr[i].slice();
                        minSingleCardCount = tmpSingleCount;
                    }
                }
            }

        // 如果下家已经报单，出单牌时出最大单排
        if (nextCardType === gameProto.cardType.SINGLE && outCardResult.cardCount === 1) {
            outCardResult.cardCount = 1;
            outCardResult.resultCard = [handCardDataArr[0]];
        }
        // else
        // // 如果下家已经报双，出对牌时出最大对排
        // if (nextCardType === gameProto.cardType.DOUBLE && outCardResult.cardCount === 2&&cardTypeResultArr[2].cardDataArr.length>0) {
        //     outCardResult.cardCount = 2;
        //     outCardResult.resultCard =cardTypeResultArr[2].cardDataArr[0];
        // }
        return outCardResult;
    };
}
module.exports = AiLogic;